likes
comments
collection
share

RxPermission源码解析

作者站长头像
站长
· 阅读数 47

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
评论
请登录