1. 程式人生 > >RxPermissions中觀察者模式解析

RxPermissions中觀察者模式解析

trigger 安裝 vat 其他 回調 null war 調用 tar

RxPermissons是什麽

RxPermissions是一款基於RxJava的Android動態權限管理庫。Android從6.0開始引入動態權限管理,不同於以往的APP安裝時就授權完畢,對於敏感權限必須由用戶手動的在APP運行過程中授權。此舉對用戶十分友好,但是對於程序員來說就不得不對權限進行管理。如果使用系統原生的方法進行管理,一般方式如下

技術分享圖片
private void requestPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {
            
// 第一次請求權限時,用戶如果拒絕,下一次請求shouldShowRequestPermissionRationale()返回true if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { // 第一次申請時提示 } else { //申請相機權限 ActivityCompat.requestPermissions(this,new
String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE); } } else { tvPermissionStatus.setTextColor(Color.GREEN); tvPermissionStatus.setText("相機權限已申請"); } }
申請相機權限

  重寫Activity或Fragment中的兩個方法

技術分享圖片
@Override
    public void onRequestPermissionsResult(int
requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == CAMERA_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { tvPermissionStatus.setTextColor(Color.GREEN); tvPermissionStatus.setText("相機權限已申請"); } else { //用戶勾選了不再詢問 //提示用戶手動打開權限 if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { Toast.makeText(this, "相機權限已被禁止", Toast.LENGTH_SHORT).show(); } } } }
View Code

  可見需要一個地方申請,然後在另外的地方再進行其他的邏輯操作。那麽如果涉及到多個權限的話,onRequestPermissionsResult()方法必然很臃腫,很混亂。那麽RxPermissions是怎麽做的呢?

RxPermissions如何使用

  1. 獲取RxPermissions對象
  2. 通過RxPermissions對象的request()方法請求權限,鏈式調用subscribe(),將授權結果與rxPermission對象綁定
  3. 對RxPermission返回的狀態進行判斷並進行下一步操作
技術分享圖片
final RxPermissions rxPermissions = new RxPermissions(this);
// Must be done during an initialization phase like onCreate
rxPermissions
    .request(Manifest.permission.CAMERA)
    .subscribe(granted -> {
        if (granted) { // Always true pre-M
           // I can control the camera now
        } else {
           // Oups permission denied
        }
    });
View Code

  代碼量並不會減少,但是整個邏輯非常簡潔。請求——>綁定——>響應。

RxPermissions解析

  RxPermissions源碼

  RxPermissions一共就只有三個類

    • Permission.用來存放具體的權限名稱及其是否被授權
    • RxPermissionFragment.Android中請求權限需要在Activity或者Fragment中響應onRequestPermissionsResult()回調,這個類用來做實際的權限請求級響應工作。
    • RxPermissions.調用RxPermissionFragment進行權限申請,並將結果轉換後響應給調用者。

  單例方式初始化

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

  進行權限請求

  我們通過三種方式的request進行權限請求,都會返回一個Observable對象。這個被觀察者通過使用ensure()方法最終調用requestImplementation(),將perissions封裝在其內部。

/**
     * Request permissions immediately, <b>must be invoked during initialization phase
     * of your application</b>.
     */
    @SuppressWarnings({"WeakerAccess", "unused"})
    public Observable<Boolean> request(final String... permissions) {
        return Observable.just(TRIGGER).compose(ensure(permissions));
    }

    /**
     * Request permissions immediately, <b>must be invoked during initialization phase
     * of your application</b>.
     */
    @SuppressWarnings({"WeakerAccess", "unused"})
    public Observable<Permission> requestEach(final String... permissions) {
        return Observable.just(TRIGGER).compose(ensureEach(permissions));
    }

    /**
     * Request permissions immediately, <b>must be invoked during initialization phase
     * of your application</b>.
     */
    public Observable<Permission> requestEachCombined(final String... permissions) {
        return Observable.just(TRIGGER).compose(ensureEachCombined(permissions));
    }

  requestImplementation通過RxPermissionsFragment進行權限請求

@TargetApi(Build.VERSION_CODES.M)
    private Observable<Permission> requestImplementation(final String... permissions) {
        // ....
        // ....
                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));
    }

  授權結果響應

  最終在RxPermissionsFragment中,通過onNext及onComplete通知觀察者狀態變化,並將授權結果返回。

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

總結

  RxPermissions是通過RxJava,將一個Permission封裝進一個Observable。接著使用RxJava的map、buffer等操作符對一個或多個Permission進行轉換,在此過程中進行權限請求。在請求權限結束後更新Obvervable的狀態,觀察者再根據狀態去讀取是否授權信息。

關於RxJava

  RxJava是一個使用觀察者模式實現的響應式庫,在處理異步時,雖然程序邏輯可能越來越復雜,但是它仍可以保持簡潔。

  參考鏈接:

  RxJava詳解

RxPermissions中觀察者模式解析