RxPermission 源码解读

使用的技术

  • RxJava
  • Fragment

原理描述

通过向申请权限的Fragment 或 Activity 中添加一个没有布局的Fragment来申请权限,使用Fragment的相关权限申请方法,来申请权限。然后通过RxJava 的 PublishSubject 特性 将授权结果发送给申请的地方

1569382934(1).jpg

代码流程

  1. 发起申请

     // 申请者可以为 activity
     public RxPermissions(@NonNull final FragmentActivity activity) {
         mRxPermissionsFragment = getLazySingleton(activity.getSupportFragmentManager());
     }
    
     // 申请者可以为 fragment
     public RxPermissions(@NonNull final Fragment fragment) {
         mRxPermissionsFragment = getLazySingleton(fragment.getChildFragmentManager());
     }
    
  2. 向当前申请者布局内添加一个没有布局的fragment

    private RxPermissionsFragment getRxPermissionsFragment(@NonNull final FragmentManager fragmentManager) {
        RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(fragmentManager);
        boolean isNewInstance = rxPermissionsFragment == null;
        if (isNewInstance) {
            rxPermissionsFragment = new RxPermissionsFragment();
            fragmentManager
                    .beginTransaction()
                    .add(rxPermissionsFragment, TAG)
                    .commitNow();
        }
        return rxPermissionsFragment;
    }
  1. 遍历授权请求 添加到观察者集合中

         // 返回Observable供申请者订阅
         @TargetApi(Build.VERSION_CODES.M)
         private Observable requestImplementation(final String... permissions) {
             List> list = new ArrayList<>(permissions.length);
             List unrequestedPermissions = new ArrayList<>();
     
     
             // 使用者可能一次申请了多个权限,将每个权限转换成一个权限被观察者,然后再将这些权限被观察者连接起来
             for (String permission : permissions) {
                 mRxPermissionsFragment.get().log("Requesting permission " + permission);
                 //已经被授权了或者是6.0以下   则直接返回携带true的权限被观察者
                 if (isGranted(permission)) {
                     list.add(Observable.just(new Permission(permission, true, false)));
                     continue;
                 }
     
                 // 被代理则直接返回false
                 if (isRevoked(permission)) {
                     list.add(Observable.just(new Permission(permission, false, false)));
                     continue;
                 }
     
                 PublishSubject subject = mRxPermissionsFragment.get().getSubjectByPermission(permission);
                 // Create a new subject if not exists
                 // 正常情况下这个地方的subject都是为空
                 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()]);
                 //触发fragment 发起权限申请的地方
                 requestPermissionsFromFragment(unrequestedPermissionsArray);
             }
     
             // concat 为串行操作符
             
             return Observable.concat(Observable.fromIterable(list));
         }
    
  2. 无布局fragment 发起权限申请

      /**
      * 开始请求权限
      *
      * @param permissions
      */
     @TargetApi(Build.VERSION_CODES.M)
     void requestPermissions(@NonNull String[] permissions) {
         requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);
     }
    
  3. 无布局fragment 处理权限 并通过PublishSubject 发送消息出去

      /**
         * 权限的回调
         *
         * 第一次请求权限时ActivityCompat.shouldShowRequestPermissionRationale=false;
         * 第一次请求权限被禁止,但未选择【不再提醒】ActivityCompat.shouldShowRequestPermissionRationale=true;
         * 允许某权限后ActivityCompat.shouldShowRequestPermissionRationale=false;
         * 禁止权限,并选中【禁止后不再询问】ActivityCompat.shouldShowRequestPermissionRationale=false;
         *
         * @param requestCode
         * @param permissions
         * @param grantResults
        */
        @TargetApi(Build.VERSION_CODES.M)
        public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
            if (requestCode != PERMISSIONS_REQUEST_CODE) return;
    
            boolean[] shouldShowRequestPermissionRationale = new boolean[permissions.length];
    
            for (int i = 0; i < permissions.length; i++) {
    
                shouldShowRequestPermissionRationale[i] = shouldShowRequestPermissionRationale(permissions[i]);
            }
    
            onRequestPermissionsResult(permissions, grantResults, shouldShowRequestPermissionRationale);
        }

        /**
         * @param permissions                          所申请的权限
         * @param grantResults                         拒绝与否的数组
         * @param shouldShowRequestPermissionRationale 是否需要显示申请理由的数组
         */
        void onRequestPermissionsResult(String permissions[], int[] grantResults, boolean[] shouldShowRequestPermissionRationale) {
            for (int i = 0, size = permissions.length; i < size; i++) {
                log("onRequestPermissionsResult  " + permissions[i]);
                // Find the corresponding subject
                PublishSubject subject = mSubjects.get(permissions[i]);
                if (subject == null) {
                    // No subject found
                    Log.e(RxPermissions.TAG, "RxPermissions.onRequestPermissionsResult invoked" +
                            " but didn't find the corresponding permission request.");
                    return;
                }
    
                //将数据结果一个个发到下游
                mSubjects.remove(permissions[i]);
                boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
                subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));
                subject.onComplete();
            }
        }

最后感想

整体库的代码比较简单,但是为我们提供了一些解决问题的思路

① 对于需要生命周期感知的问题,我们可以委托一个fragment来进行管理
② 使用PublishSubject 能够轻松实现一些基于观察者模式的需求

你可能感兴趣的:(RxPermission 源码解读)