天天看點

RxPermissions源碼解析

前言

AndroidM(6.0)開始,系統增加了運作時動态權限,目的在于保護使用者隐私,防止一些敏感的危險權限在應用安裝時被随意擷取,使用者可以清晰地選擇是否允許app某項權限,就算沒有給予某個權限,也不影響其他功能的使用,不至于令使用者無法安裝。以下權限都被列為危險權限,即需要運作時動态擷取的權限。

身體傳感器
月曆
攝像頭
通訊錄
地理位置
麥克風
電話
短信
存儲空間
           

原始使用方法

第一步是先判斷目前是否已經擷取到該權限了;第 2 步申請對應的權限;第 3 步在 Activity 或者 Fragment 中處理擷取權限的結果。具體的實作步驟如下:

  • step 1:判斷權限是否已經擷取。
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {//第一步,檢查使用者是否具有該權限

    // Permission is not granted
    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {
        // Show an explanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.
    } else {
        // No explanation needed; request the permission
        ActivityCompat.requestPermissions(thisActivity,//第二步,申請對應權限
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
} else {
    // Permission has already been granted
}
           
  • step 2:申請權限
ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[]{Manifest.permission.READ_CONTACTS},
                                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);
           
  • step 3:結果處理
@Override
public void onRequestPermissionsResult(int requestCode,
        String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted, yay! Do the
                // contacts-related task you need to do.
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request.
    }
}
           

RxPermissions

[RxPermissions**](https://github.com/tbruyelle/RxPermissions)**原始的操作的方式其實類似于

startActivityForResult

這種啟動Activity的方法,也是會有具體的回調方法,但是如果每次都需要這樣寫太過于繁瑣,是以需要對其進行封裝,而

RxPermissions

這個庫就對其進行了很好的封裝該庫允許将

RxJava

與新的Android M權限模型一起使用。基本用法:

final RxPermissions rxPermissions = new RxPermissions(this); // where this is an Activity or Fragment instance
rxPermissions
    .request(Manifest.permission.CAMERA)
    .subscribe(granted -> {
        if (granted) { // Always true pre-M
           // I can control the camera now
        } else {
           // Oups permission denied
        }
    });
           

還有其他方法參考看https://github.com/tbruyelle/RxPermissions

整體介紹

整個庫裡面,其實就隻有 4 個類:RxPermissions、RxPermissionsFragment、Permission

  • RxPermissions 最主要的實作類,利用 rxjava,為我們提供了友善權限申請的類
  • RxPermissionsFragment 是一個 fragment,主要的動态權限擷取類
  • Permission 定義的權限的 model 類
  • BuildConfig 沒什麼用的配置類

源碼分析

RxPermissions 執行個體建立

RxPermissions.Lazy<RxPermissionsFragment> mRxPermissionsFragment;

    public RxPermissions(@NonNull FragmentActivity activity) {
        this.mRxPermissionsFragment = this.getLazySingleton(activity.getSupportFragmentManager());
    }

    public RxPermissions(@NonNull Fragment fragment) {
        this.mRxPermissionsFragment = this.getLazySingleton(fragment.getChildFragmentManager());
    }

    @NonNull
    private RxPermissions.Lazy<RxPermissionsFragment> getLazySingleton(@NonNull final FragmentManager fragmentManager) {
        return new RxPermissions.Lazy<RxPermissionsFragment>() {
            private RxPermissionsFragment rxPermissionsFragment;

            public synchronized RxPermissionsFragment get() {
                if (this.rxPermissionsFragment == null) {
                    this.rxPermissionsFragment = RxPermissions.this.getRxPermissionsFragment(fragmentManager);//1 擷取RxPermissionsFragment的方法
                }

                return this.rxPermissionsFragment;
            }
        };
    }

           

我們可以看到,上面的代碼中,執行個體化 RxPermissions 的時候,裡面先建立了一個 RxPermissionsFragment 的執行個體。關鍵代碼1處調用

getRxPermissionsFragment

 這個方法。

private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
        //  查找 RxPermissionsFragment 是否已經被添加了
        RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
        boolean isNewInstance = rxPermissionsFragment == null;
          // 如果還沒有存在,則建立Fragment,并添加到Activity中
        if (isNewInstance) {
            rxPermissionsFragment = new RxPermissionsFragment();
            FragmentManager fragmentManager = activity.getFragmentManager();
            fragmentManager
                    .beginTransaction()
                    .add(rxPermissionsFragment, TAG)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return rxPermissionsFragment;
    }
           

在 getRxPermissionsFragment() 這個方法中,首先是先查找目前是否已經添加了這個 rxPermissionsFragment 的執行個體,如果已經添加,那麼直接傳回已經添加的執行個體,如果沒有添加過的話,那麼就重新再建立一個 RxPermissionsFragment 執行個體并送出;

// 利用tag去找是否已經有該Fragment的執行個體
private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {
        return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);    
}
           

通過以上的代碼可以知道,在建立RxPermissions的對象中,其實就是擷取Fragment的執行個體而已,既然這樣,我們就需要到這個Fragment的實作中,看它在被建立的時候做了什麼事情

// Fragment的構造方法
public RxPermissionsFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 禁止橫豎屏切換時的Fragment的重建
    setRetainInstance(true);
}
           

到此,rxPermissionsFragment 的執行個體化已經完成,接着我們需要看看 request 這個方法中實作了什麼。

request 方法

public Observable<Boolean> request(final String... permissions) {
        return Observable.just(TRIGGER).compose(ensure(permissions));
    }
    static final Object TRIGGER = new Object();

           

從上面的代碼中,我們可以看到,request 方法中需要傳入的參數是一個 權限的數組,傳回值是 Observable對象。Observable.just(TRIGGER) 是快捷建立一個 Observable的方式,由于 TRIGGER 是一個空的 Object 對象,是以 TRIGGER 就是一個占位符而已,Observable.just(TRIGGER) 建立的是一個 Observable,之後通過 compose 将 Observable轉化為 Observable并傳回。在 compose 中需要的參數是一個 

ObservableTransformer

,接着看 ensure() 這個方法。

ensure(permissions);

public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
        // 建立一個Transformer對象傳回
        return new ObservableTransformer<T, Boolean>() {
            @Override
            public ObservableSource<Boolean> apply(Observable<T> o) {
                //request(o, permissions) 方法傳回 Observable<Permission> 對象
                return request(o, permissions)
                        // 将 Observable<Permission> 轉換為 Observable<Boolean>,在這裡會等待所有的權限都傳回了一次性發射資料。
                        .buffer(permissions.length)
                        .flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
                            @Override
                            public ObservableSource<Boolean> apply(List<Permission> permissions) throws Exception {
                                // 如果permissions為空那麼直接傳回Observable.empty();
                                if (permissions.isEmpty()) {
                                    // Occurs during orientation change, when the subject receives onComplete.
                                    // In that case we don't want to propagate that empty list to the
                                    // subscriber, only the onComplete.
                                    return Observable.empty();
                                }
                                // Return true if all permissions are granted.
                                for (Permission p : permissions) {
                                    if (!p.granted) {
                                        return Observable.just(false);
                                    }
                                }
                                return Observable.just(true);
                            }
                        });
            }
        };
    }

           

在 ensure 的這個方法中,最終會傳回的是 ObservableTransformer<T, Boolean> 對象。接着我們看看 ObservableTransformer 的匿名實作類裡面的 apply 方法,這裡實作的就是将 Observable轉化為 Observable的操作。我們對 apply 這個方法裡面的代碼進行簡化一下。

return request(o,permissions)
    .buffer(permissions.length)
    .flatMap(new Function<List<Permission>, ObservableSource<Boolean>>{});
           
  • request() 方法傳回 Observable對象
  • buffer(len) 操作符将一個 Observable變換為 Observable,原來的 Observable 正常發射資料,變換産生的 Observable 發射這些資料的緩存集合。buffer 将資料緩存到一個集合當中,然後在适當(比如:所有請求的權限結果都傳回了)的時機一起發送。
  • flatMap() 方法将 Observable轉化為 Observable

request(o, permissions);

private Observable<Permission> request(final Observable<?> trigger, final String... permissions) {
        if (permissions == null || permissions.length == 0) {
            throw new IllegalArgumentException("RxPermissions.request/requestEach requires at least one input permission");
        }
        return oneOf(trigger, pending(permissions))
                .flatMap(new Function<Object, Observable<Permission>>() {
                    @Override
                    public Observable<Permission> apply(Object o) throws Exception {
                        return requestImplementation(permissions);
                    }
                });
    }

           

在 request 這個方法裡面,其實 oneOf() 和 pending() 方法我們可以忽略的,主要的話,我們應該關注 requestImplementation(final String… permissions) 這個方法,在這個方法裡面,主要實作了權限的請求。

requestImplementation

@TargetApi(Build.VERSION_CODES.M)
    private Observable<Permission> requestImplementation(final String... permissions) {
        List<Observable<Permission>> list = new ArrayList<>(permissions.length);
        List<String> unrequestedPermissions = new ArrayList<>();

        // In case of multiple permissions, we create an Observable for each of them.
        // At the end, the observables are combined to have a unique response.
        for (String permission : permissions) {
            mRxPermissionsFragment.log("Requesting permission " + permission);
            if (isGranted(permission)) {
                // Already granted, or not Android M
                // Return a granted Permission object.
                // 權限已經被同意或者不是 Android 6.0 以上版本,建立一個 同意的 Permission 對象。
                list.add(Observable.just(new Permission(permission, true, false)));
                continue;
            }

            if (isRevoked(permission)) {
                // 權限被拒絕,傳回一個 拒絕的 Permission 對象。
                list.add(Observable.just(new Permission(permission, false, false)));
                continue;
            }

            PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);
            // 如果 subject 不存在,那麼建立一個 subject。
            if (subject == null) {
                unrequestedPermissions.add(permission);
                subject = PublishSubject.create();
                mRxPermissionsFragment.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));
    }

複制代碼
           

onRequestPermissionsResult()

@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);
    }

    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<Permission> 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();
        }
    }

複制代碼
           

RxJava 操作符

Observable.just()

just 操作符是将一個對象轉化為 Observable 的操作符。這個對象可以是一個數字、字元串或者是數組對象等,是 RxJava 中快速建立一個 Observable 對象的操作符。如果有 subscriber 訂閱的話,那麼會依次調用 onNext() 和 OnComplete() 方法。是以這裡隻是建立了一個 Observable 對象,友善後續的調用。

compose(Transformer)操作符

compose 操作符是對 Observable 對象的整體轉化。例如:通過 Transformer,我們可以将 Observable 對象轉換成 Observable 對象了。

public static ObservableTransformer<String,Boolean> getTransformer(){
        return new ObservableTransformer<String, Boolean>() {
            @Override
            public ObservableSource<Boolean> apply(Observable<String> upstream) {
                return upstream.flatMap(new Function<String, ObservableSource<Boolean>>() {
                    @Override
                    public ObservableSource<Boolean> apply(String s) throws Exception {
                        return Observable.just(true);
                    }
                });
            }
        };
    }
    /**
     * 線程切換
     * @return
     */
    public static <T> ObservableTransformer<T,T> getScheduler(){
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

           

buffer 操作符

buffer 操作符将一個 Observable 變換為另一個,原來的 Observable 正常發射資料,變換産生的 Observable 發射這些資料的緩存集合。buffer将資料緩存到一個集合當中,然後在适當的時機一起發送。 buffer(count) 以清單(List)的形式發射非重疊的緩存,每一個緩存至多包含來自原始Observable的count項資料(最後發射的清單資料可能少于count項)

  • 例如:緩存 2 個資料之後,再發送資料(調用 buffer(count) 函數)
Observable.just(1,2,3,4,5,6)
                        .buffer(2)
                        .subscribe(integers -> {
                            Log.i(TAG, "accept size: "+integers.size());
                            for (Integer integer : integers) {
                                Log.i(TAG, "accept: "+integer);
                            }
                        });
複制代碼
           
  • 輸出結果
2018-12-14 11:16:28.452 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:16:28.452 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 1
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 2
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 5
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 6
複制代碼
           
  • 例如:緩存 3 個資料,再發送資料,每次移動 1 步
Observable.just(1,2,3,4)
                        .buffer(3,1)
                        .subscribe(integers -> {
                            Log.i(TAG, "accept size: "+integers.size());
                            for (Integer integer : integers) {
                                Log.i(TAG, "accept: "+integer);
                            }
                        });
           
  • 輸出結果
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 1
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 2
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 2
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 1
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
複制代碼
           

concat 操作符

是接收若幹個Observables,發射資料是有序的,不會交叉。

Subject

  • 作為 Observable 和 Observer 之間的橋梁
  • 可以當做 Observable
  • 可以當做 Observer

PublishSubject

繼承至 Subject,它的 Observer 隻會接收到 PublishSubject 被訂閱之後發送的資料。示例代碼如下;我們隻會接收到 publishSubject3 和 publishSubject4;

PublishSubject<String> publishSubject = PublishSubject.create();
                publishSubject.onNext("publishSubject1");
                publishSubject.onNext("publishSubject2");
                publishSubject.subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        Log.i(TAG, "accept: "+s);
                    }
                });
                publishSubject.onNext("publishSubject3");
                publishSubject.onNext("publishSubject4");

           
  • 執行結果
2018-12-14 11:33:18.168 29916-29916/com.luwei.lwbaselib I/LwBaseActivity: accept: publishSubject3
2018-12-14 11:33:18.168 29916-29916/com.luwei.lwbaselib I/LwBaseActivity: accept: publishSubject4
           

總結

可以看到,在Fragment被建立時,并沒有重寫

onCreateView

()方法,來進行布局檔案的加載,隻是重寫了onCreate()方法,然後禁止了橫豎屏Fragment的重建,這就代表說,這個Fragment是一個沒有布局的隐形Fragment,不會在螢幕上展示出來,但是這個Fragment卻是關鍵,權限的申請與申請結果的回調都是在Fragment中完成的,這樣,我們才不需要為申請結果重寫回調方法

------ 本文結束 ------