RxPermission源码解析

RxPermission是一个Android处理权限的工具类,可以方便的和RxJava结合发起权限请求。这个库和其他权限请求工具的区别在于,可以不用处理的权限请求的结果回调onRequestPermissionsResult()方法,我们来通过源码解析来看下是如何实现的。

使用方式:

1、可以调用RxPermissions的request()方法,该方法返回一个Observable对象,代表请求权限的结果。改方法可以同时请求多个权限,只有所有权限都允许后表示成功,如果有一个权限被禁止,则回调结果为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.im/post/5bde798c518825171140d6f2

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » RxPermission源码解析

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址