RxPermission源码解析
RxPermission源码解析
RxPermission是一个Android处理权限的工具类,可以方便的和RxJava结合发起权限请求。这个库和其他权限请求工具的区别在于,可以不用处理的权限请求的结果回调onRequestPermissionsResult()方法,我们来通过源码解析来看下是如何实现的。
使用方式:
1、可以调用RxPermissions的request()方法,该方法返回一个Observable对象,代表请求权限的结果。该方法可以同时请求多个权限,当所有权限都被允许后结果为true;如果有一个权限被禁止,则回调结果为false。
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions.request(permission.WRITE_EXTERNAL_STORAGE, permission.CAMERA)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if(aBoolean){
//permission granted
}
}
});
如果要获取请求的每个权限的结果,可以使用requestEach()方法。该方法的回调会被调用多次,回调的Permission表示每个权限请求的结果。
rxPermissions.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE, permission.CAMERA)
.subscribe(new Consumer<Permission>() {
@Override
public void accept(Permission permission) throws Exception {
//check permission
}
});
2、一般开发中,通常是点击某个按钮后才请求权限,如果使用了RxBinding库处理UI事件,可以很方便的和RxPermissions一起进行权限请求。
RxView.clicks(findViewById(R.id.enableCamera))
// Ask for permissions when button is clicked
.compose(rxPermissions.ensureEach(permission.CAMERA))
.subscribe(new Consumer<Permission>() {
@Override
public void accept(Permission permission) {
Log.i(TAG, "Permission result " + permission);
if (permission.granted) {
}
});
RxPermissions提供ensure(),ensureEach()和ensureEachCombined()方法,这些方法会返回一个ObservableTransformer<T, Permission>对象,结合RxJava中的compose操作符,可以将View事件转换为一个权限请求。
ensure()方法类似request()方法,结果回调的参数为Boolean类型,请求的全部权限都成功时为true,否则为false。
ensureEach()方法类似requestEach()方法,请求多个权限时,结果回调会被调用多次,可以获取到每个权限的请求结果。
ensureEachCombined()方法会结果会回调一次,回调的参数为Permission类型,这个permission参数和requestEach()的不太一样,在这个permission对象中会包含所有请求的名字,并且所有权限都成功的话,permission的granted属性会为true,否则为false。
源码解析
从RxPermissions的构造方法开始
public RxPermissions(@NonNull final FragmentActivity activity) {
mRxPermissionsFragment = getLazySingleton(activity.getSupportFragmentManager());
}
public RxPermissions(@NonNull final Fragment fragment) {
mRxPermissionsFragment = getLazySingleton(fragment.getChildFragmentManager());
}
RxPermissions针对Activity和Fragment提供了两个构造方法,最终都是获取FragmentManager再调用getLazySingleton()方法。getLazeSingleton方法的源码如下:
@NonNull
private Lazy<RxPermissionsFragment> getLazySingleton(@NonNull final FragmentManager fragmentManager) {
return new Lazy<RxPermissionsFragment>() {
private RxPermissionsFragment rxPermissionsFragment;
@Override
public synchronized RxPermissionsFragment get() {
if (rxPermissionsFragment == null) {
rxPermissionsFragment = getRxPermissionsFragment(fragmentManager);
}
return rxPermissionsFragment;
}
};
}
这个方法返回了一个Lazy对象,在lazy的对象的get()方法中创建了一个fragment对象并保存下来。Lazy是一个实现懒加载的工具类,在第一次调用get()方法时,会执行创建操作,并且将创建的对象保存下来。
@FunctionalInterface
public interface Lazy<V> {
V get();
}
创建RxPermissions对象后,便可以进行权限请求,先看RxPermissions的request()方法
public Observable<Boolean> request(final String... permissions) {
return Observable.just(TRIGGER).compose(ensure(permissions));
}
TRIGGER是一个Object对象,用于开始请求,并且兼容RxBinding相关的操作。
static final Object TRIGGER = new Object();
request()方法内部实际上是调用了ensure(),看下ensure()的代码
public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
return new ObservableTransformer<T, Boolean>() {
@Override
public ObservableSource<Boolean> apply(Observable<T> o) {
return request(o, permissions)
// Transform Observable<Permission> to Observable<Boolean>
.buffer(permissions.length)
.flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(List<Permission> permissions) {
if (permissions.isEmpty()) {
return Observable.empty();
}
for (Permission p : permissions) {
if (!p.granted) {
return Observable.just(false);
}
}
return Observable.just(true);
}
});
}
};
}
ensure()方法中创建了个一个RxJava中的ObservableTransformer对象,将一个泛型T类型的Observable装换成一个ObservableSource对象,ObservableSource是Observable的父类型,这个Boolean类型代表请求权限的结果。
在ObservableTransformer的apply()方法中,调用了request(final Observable<?> trigger, final String... permissions)方法,然后使用buffer操作符缓存所有的请求结果,在flatMap操作符中将结果转换为Boolean类型,如果所有的权限都授权成功则返回true,否则返回false。
在request(final Observable<?> trigger, final String... permissions)方法中有调用了requestImplementation()方法
private Observable<Permission> requestImplementation(final String... permissions) {
List<Observable<Permission>> list = new ArrayList<>(permissions.length);
List<String> unrequestedPermissions = new ArrayList<>();
for (String permission : permissions) {
mRxPermissionsFragment.get().log("Requesting permission " + permission);
if (isGranted(permission)) {
list.add(Observable.just(new Permission(permission, true, false)));
continue;
}
if (isRevoked(permission)) {
list.add(Observable.just(new Permission(permission, false, false)));
continue;
}
PublishSubject<Permission> subject = mRxPermissionsFragment.get().getSubjectByPermission(permission);
// Create a new subject if not exists
if (subject == null) {
unrequestedPermissions.add(permission);
subject = PublishSubject.create();
mRxPermissionsFragment.get().setSubjectForPermission(permission, subject);
}
list.add(subject);
}
if (!unrequestedPermissions.isEmpty()) {
String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
requestPermissionsFromFragment(unrequestedPermissionsArray);
}
return Observable.concat(Observable.fromIterable(list));
}
在这个方法中,会创建两个列表,list为List<Observable>类型,包含每个权限的请求;unrequestedPermissions为List类型,表示需要发起请求的权限。
这里首先会遍历需要请求的所有权限,如果已经该权限已经被授予,则创建一个granted字段为true的Permission对象加入到list中;如果权限被撤回,则创建一个granted字段为false的Permission对象加入list中。如果该权限没有被授予也没有被撤回,就去请求权限。
具体的方式是调用RxPermissionsFragment对象的getSubjectByPermission()方法获取一个PublishSubject对象,Subject是一种既可以作为Observable也可以作为Observer的对象,集成自Observable类,并实现了Observer接口。如果获取到subject对象,表示该权限正在被请求;如果返回null,表示该权限未被请求,会创建一个新的PublishSubject对象,并调用setSubjectForPermission方法保存下来,同时将该权限保存在unrequestedPermissions列表中。
如果unrequestedPermissions不为空,表示存在需要请求的权限,会调用requestPermissionsFromFragment()去请求权限。
最后,使用fromIterable和concat操作符将结果转换为Observable类型。
接下来看requestPermissionsFromFragment()方法
void requestPermissionsFromFragment(String[] permissions) {
mRxPermissionsFragment.get().log("requestPermissionsFromFragment " + TextUtils.join(", ", permissions));
mRxPermissionsFragment.get().requestPermissions(permissions);
}
打印日志后调用的RxPermissionsFragemnt的requestPermissions方法。而RxPermissionsFragemnt的requestPermissions方法直接发起了权限请求。在RxPermissionsFragemnt的void onRequestPermissionsResult() 回调中处理请求的结果。
void onRequestPermissionsResult(String permissions[], int[] grantResults, boolean[] shouldShowRequestPermissionRationale) {
for (int i = 0, size = permissions.length; i < size; i++) {
PublishSubject<Permission> subject = mSubjects.get(permissions[i]);
if (subject == null) {
// No subject found
return;
}
mSubjects.remove(permissions[i]);
boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));
subject.onComplete();
}
}
在回调中会找到每个权限对应的subject对象,创建一个Permission对象保存权限的结果,通过subject将结果发送出去。
再回到ensure()方法,权限请求结果发射后,会这里收到回调。
public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
return new ObservableTransformer<T, Boolean>() {
@Override
public ObservableSource<Boolean> apply(Observable<T> o) {
return request(o, permissions)
// Transform Observable<Permission> to Observable<Boolean>
.buffer(permissions.length)
.flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(List<Permission> permissions) {
if (permissions.isEmpty()) {
return Observable.empty();
}
for (Permission p : permissions) {
if (!p.granted) {
return Observable.just(false);
}
}
return Observable.just(true);
}
});
}
};
}
如上所述,ensure方法会将权限的请求结果转换为Boolean类型。
同样的,与request()对应的requestEach()方法在内部会调用ensureEach()方法, 我们来看下ensureEach()的实现
public <T> ObservableTransformer<T, Permission> ensureEach(final String... permissions) {
return new ObservableTransformer<T, Permission>() {
@Override
public ObservableSource<Permission> apply(Observable<T> o) {
return request(o, permissions);
}
};
}
ensureEach()同样是创建了一个ObservableTransformer对象,与ensure()不同的是将Observable转换为ObservableSource对象。在下游可以接收到每个权限的结果,并做相应的处理。
除了ensure()和ensureEach()方法外,RxPermissions还提供了一个ensureEachCombined()方法,实现如下
public <T> ObservableTransformer<T, Permission> ensureEachCombined(final String... permissions) {
return new ObservableTransformer<T, Permission>() {
@Override
public ObservableSource<Permission> apply(Observable<T> o) {
return request(o, permissions)
.buffer(permissions.length)
.flatMap(new Function<List<Permission>, ObservableSource<Permission>>() {
@Override
public ObservableSource<Permission> apply(List<Permission> permissions) {
if (permissions.isEmpty()) {
return Observable.empty();
}
return Observable.just(new Permission(permissions));
}
});
}
};
}
该方法与ensure方法类似,同样会对请求的结果进行处理,只是是将所有的结果转换为一个Permission对象,而不是一个Boolean值。Permission类有一个Permission(List permissions)构造函数,在一个Permission对象中存贮多个权限的结果
public Permission(List<Permission> permissions) {
name = combineName(permissions);
granted = combineGranted(permissions);
shouldShowRequestPermissionRationale = combineShouldShowRequestPermissionRationale(permissions);
}
combineName()方法会多个权限的名称通过“,”连接成一个字符串;combineGranted()方法当所有权限都授予时会返回ture,否则返回false;combineShouldShowRequestPermissionRationale()方法则当任意一个权限的shouldShowRequestPermissionRationale为ture时返回ture,否则返回false。下面是combineName()的源码
private String combineName(List<Permission> permissions) {
return Observable.fromIterable(permissions)
.map(new Function<Permission, String>() {
@Override
public String apply(Permission permission) throws Exception {
return permission.name;
}
}).collectInto(new StringBuilder(), new BiConsumer<StringBuilder, String>() {
@Override
public void accept(StringBuilder s, String s2) throws Exception {
if (s.length() == 0) {
s.append(s2);
} else {
s.append(", ").append(s2);
}
}
}).blockingGet().toString();
}
总结
RxPermissions通过在Activity添加一个fragment来请求权限和处理权限的结果,避免单独再处理onRequestPermissionsResult回调。并提供request和ensure等一系列方法,可以和RxJava,RxBinding方便的结合在一起。
转载自:https://juejin.cn/post/6844903704072568846