Android RxPermissions源碼分析

一蔚晨、感悟

看了源碼后乍钻,有個感慨,就是以后源碼的分析還是自己先看铭腕,看不懂再去看人家寫的银择,因為自己看思路把握得更加好,看人家的也更容易看懂谨履。

二欢摄、使用

RxPermissions rxPermissionss = new RxPermissions(this);
rxPermissionss.request(Manifest.permission.READ_PHONE_STATE)
                    .subscribe(new Subscriber<Boolean>(this) {

                        @Override
                        public void onNext(Boolean aBoolean) {
                            if (aBoolean) {
                               //權(quán)限同意后的操作
                            } else {
                             //權(quán)限拒絕后的操作
                            }
                        }
                    });

三、分析

fragment簡稱碎片笋粟,可以嵌入到Activity中怀挠,沒想到它還可以這樣用

對比:

一般的動態(tài)請求權(quán)限是
詢問-->同意授權(quán)/不同意授權(quán)-->method-->end
詢問-->回調(diào)-->同意/不同意授權(quán)-->end
RxPermissions
詢問-->同意授權(quán)/不同意授權(quán)-->method-->end
詢問-->(fragment回調(diào))-->同意/不同意授權(quán)-->end

思路(前提是已經(jīng)了解了rxjava基礎(chǔ))

可見RxPermissions會直接隱藏掉了回調(diào)的步驟,原因就是利用rxjava的觀察者模式
1.對于授權(quán)或者沒有授權(quán)的情況害捕,換句話就是已經(jīng)有結(jié)果了的情況绿淋,會直接返回帶有結(jié)果的Observable
2.對于需要詢問的情況,記錄需要詢問的權(quán)限尝盼,然后調(diào)用詢問的方法吞滞,之后將結(jié)果以同樣的方式返回Observable
3.有了帶結(jié)果的Observable,就可以直接根據(jù)結(jié)果調(diào)方法

源碼分析

1.為Activity添加fragment

private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
        RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
        boolean isNewInstance = rxPermissionsFragment == null;
        if (isNewInstance) {
            rxPermissionsFragment = new RxPermissionsFragment();
            FragmentManager fragmentManager = activity.getFragmentManager();
            fragmentManager
                    .beginTransaction()
                    .add(rxPermissionsFragment, TAG)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return rxPermissionsFragment;
    }

    private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {
        return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);
    }

2.將權(quán)限傳遞過來

 public Observable<Boolean> request(final String... permissions) {
        return Observable.just(null).compose(ensure(permissions));
    }

3.看ensure方法

public Observable.Transformer<Object, Boolean> ensure(final String... permissions) {
        return new Observable.Transformer<Object, Boolean>() {
            @Override
            public Observable<Boolean> call(Observable<Object> o) {
                return request(o, permissions)
                        // Transform Observable<Permission> to Observable<Boolean>
                        .buffer(permissions.length)
                        .flatMap(new Func1<List<Permission>, Observable<Boolean>>() {
                            @Override
                            public Observable<Boolean> call(List<Permission> permissions) {
                                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);
                            }
                        });
            }
        };
    }

首先關(guān)注flatMap操作符后的操作,最后返回權(quán)限的集合裁赠,遍歷集合殿漠,通過封裝權(quán)限類的第二個參數(shù)得到是否同意權(quán)限,返回布爾值佩捞。
再往上看buffer绞幌,目的是將所有權(quán)限以一個集合返回
再往上看requset操作符,點擊進(jìn)去

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 Func1<Object, Observable<Permission>>() {
                    @Override
                    public Observable<Permission> call(Object o) {
                        return requestImplementation(permissions);
                    }
                });
    }

進(jìn)而看requestImplementation方法

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)) {
                // 同意權(quán)限情況
                list.add(Observable.just(new Permission(permission, true, false)));
                continue;
            }

            if (isRevoked(permission)) {
                // 拒絕權(quán)限情況
                list.add(Observable.just(new Permission(permission, false, false)));
                continue;
            }

            PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);
            // Create a new subject if not exists
            if (subject == null) {
                //需要詢問的權(quán)限的添加
                unrequestedPermissions.add(permission);
                subject = PublishSubject.create();
                mRxPermissionsFragment.setSubjectForPermission(permission, subject);
            }

            list.add(subject);
        }

        if (!unrequestedPermissions.isEmpty()) {
         //需要詢問的權(quán)限列表
            String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
        //請求權(quán)限詢問
    requestPermissionsFromFragment(unrequestedPermissionsArray);
        }
        return Observable.concat(Observable.from(list));
    }

可以先看注釋一忱,已經(jīng)有權(quán)限請求結(jié)果的就不用再次詢問了莲蜘,直接just 發(fā)送就好。對于新的權(quán)限請求帘营,則需要調(diào)用mRxPermissionsFragment中的方法進(jìn)行詢問票渠,詢問后onNext()發(fā)送出去。
方法的最后返回Observable.concat(Observable.from(list))芬迄,是所有的請求有序發(fā)出
有關(guān)詢問的方法问顷,細(xì)看mRxPermissionsFragment中的此方法

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

完成到這里,就基本上將所有請求全部發(fā)出薯鼠,而且經(jīng)歷多次轉(zhuǎn)換拿到了權(quán)限的請求結(jié)果择诈,被觀察者已經(jīng)完成任務(wù)了,剩下的就交給觀察者啦出皇,回看文章開頭的使用方法吧

喵印~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末羞芍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子郊艘,更是在濱河造成了極大的恐慌荷科,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纱注,死亡現(xiàn)場離奇詭異畏浆,居然都是意外死亡,警方通過查閱死者的電腦和手機狞贱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門刻获,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瞎嬉,你說我怎么就攤上這事蝎毡。” “怎么了氧枣?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵沐兵,是天一觀的道長。 經(jīng)常有香客問我便监,道長扎谎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮毁靶,結(jié)果婚禮上胧奔,老公的妹妹穿的比我還像新娘。我一直安慰自己老充,他們只是感情好葡盗,可當(dāng)我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布螟左。 她就那樣靜靜地躺著啡浊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胶背。 梳的紋絲不亂的頭發(fā)上巷嚣,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機與錄音钳吟,去河邊找鬼廷粒。 笑死,一個胖子當(dāng)著我的面吹牛红且,可吹牛的內(nèi)容都是我干的坝茎。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼暇番,長吁一口氣:“原來是場噩夢啊……” “哼嗤放!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起壁酬,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤次酌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后舆乔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岳服,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年希俩,在試婚紗的時候發(fā)現(xiàn)自己被綠了吊宋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡颜武,死狀恐怖璃搜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盒刚,我是刑警寧澤腺劣,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站因块,受9級特大地震影響橘原,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一趾断、第九天 我趴在偏房一處隱蔽的房頂上張望拒名。 院中可真熱鬧,春花似錦芋酌、人聲如沸增显。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽同云。三九已至,卻和暖如春堵腹,著一層夾襖步出監(jiān)牢的瞬間炸站,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工疚顷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旱易,地道東北人。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓腿堤,卻偏偏與公主長得像阀坏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笆檀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,876評論 2 361