RxPermissions 源码解析之举一反三
[toc]
RxPermissions 源碼解析
簡(jiǎn)介
RxPermissions 是基于 RxJava 開發(fā)的用于幫助 在Android 6.0 中處理運(yùn)行時(shí)權(quán)限檢測(cè)的框架。在 Android 6.0 中增加了對(duì)危險(xiǎn)權(quán)限的動(dòng)態(tài)申請(qǐng),而不是像 Android 6.0 之前的默認(rèn)全部獲取的方式。
原始動(dòng)態(tài)權(quán)限的獲取
如果按照以往的獲取權(quán)限方式的話,那么我們獲取權(quán)限一般需要有 3 個(gè)步驟,第一步是先判斷當(dāng)前是否已經(jīng)獲取到該權(quán)限了;第 2 步申請(qǐng)對(duì)應(yīng)的權(quán)限;第 3 步在 Activity 或者 Fragment 中處理獲取權(quán)限的結(jié)果。具體的實(shí)現(xiàn)步驟如下:
- step 1:判斷權(quán)限是否已經(jīng)獲取。
- step 2:申請(qǐng)權(quán)限
- step 3:結(jié)果處理
RxPermissions 的簡(jiǎn)單使用
其實(shí) RxPermissions 的使用方式有兩種
- 方式 1:
- 方式 2:結(jié)合 RxBinding 來使用
源碼分析
整體介紹
接著我們來對(duì)這個(gè) RxPermissions 進(jìn)行一個(gè)源碼的解析,但是打開源碼的時(shí)候,我們可以發(fā)現(xiàn),這個(gè)庫(kù)里面,其實(shí)就只有 3 個(gè)類:RxPermissions、RxPermissionsFragment、Permission
- RxPermissions
- 最主要的實(shí)現(xiàn)類,利用 rxjava,為我們提供了方便權(quán)限申請(qǐng)的類
- RxPermissionsFragment
- 是一個(gè) fragment,主要的動(dòng)態(tài)權(quán)限獲取類
- Permission
- 定義的權(quán)限的 model 類
源碼分析
RxPermissions 實(shí)例創(chuàng)建
對(duì)于源碼的分析,我們應(yīng)該先從簡(jiǎn)單的使用入手。下面我們可以先看看實(shí)例化 RxPermissionsFragment 的時(shí)候是做了什么?
RxPermissionsFragment mRxPermissionsFragment;public RxPermissions(@NonNull Activity activity) {mRxPermissionsFragment = getRxPermissionsFragment(activity);}復(fù)制代碼我們可以看到,上面的代碼中,實(shí)例化 RxPermissionsFragment 的時(shí)候,里面先創(chuàng)建了一個(gè) RxPermissionsFragment 的實(shí)例。我們?cè)俳又?getRxPermissionsFragment 這個(gè)方法的實(shí)現(xiàn)。
private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {// 查找 RxPermissionsFragment 是否已經(jīng)被添加了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;}復(fù)制代碼在 getRxPermissionsFragment() 這個(gè)方法中,首先是先查找當(dāng)前是否已經(jīng)添加了這個(gè) rxPermissionsFragment 的實(shí)例,如果已經(jīng)添加,那么直接返回已經(jīng)添加的實(shí)例,如果沒有添加過的話,那么就重新再創(chuàng)建一個(gè) RxPermissionsFragment 實(shí)例并提交;
private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);} 復(fù)制代碼到此,rxPermissionsFragment 的實(shí)例化已經(jīng)完成,接著我們需要看看 request 這個(gè)方法中實(shí)現(xiàn)了什么。
request 方法
public Observable<Boolean> request(final String... permissions) {return Observable.just(TRIGGER).compose(ensure(permissions));} 復(fù)制代碼 static final Object TRIGGER = new Object(); 復(fù)制代碼從上面的代碼中,我們可以看到,request 方法中需要傳入的參數(shù)是一個(gè) 權(quán)限的數(shù)組,返回值是 Observable 對(duì)象。Observable.just(TRIGGER) 是快捷創(chuàng)建一個(gè) Observable 的方式,由于 TRIGGER 是一個(gè)空的 Object 對(duì)象,所以 TRIGGER 就是一個(gè)占位符而已,Observable.just(TRIGGER) 創(chuàng)建的是一個(gè) Observable,之后通過 compose 將 Observable 轉(zhuǎn)化為 Observable 并返回。在 compose 中需要的參數(shù)是一個(gè) ObservableTransformer,那么我們接著看 ensure() 這個(gè)方法。
ensure(permissions);
public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {// 創(chuàng)建一個(gè)Transformer對(duì)象返回return new ObservableTransformer<T, Boolean>() {@Overridepublic ObservableSource<Boolean> apply(Observable<T> o) {//request(o, permissions) 方法返回 Observable<Permission> 對(duì)象return request(o, permissions)// 將 Observable<Permission> 轉(zhuǎn)換為 Observable<Boolean>,在這里會(huì)等待所有的權(quán)限都返回了一次性發(fā)射數(shù)據(jù)。.buffer(permissions.length).flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {@Overridepublic 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);}});}};}復(fù)制代碼在 ensure 的這個(gè)方法中,最終會(huì)返回的是 ObservableTransformer<T, Boolean> 對(duì)象。接著我們看看 ObservableTransformer 的匿名實(shí)現(xiàn)類里面的 apply 方法,這里實(shí)現(xiàn)的就是將 Observable 轉(zhuǎn)換為 Observable 的操作。我們對(duì) apply 這個(gè)方法里面的代碼進(jìn)行簡(jiǎn)化一下。
return request(o,permissions).buffer(permissions.length).flatMap(new Function<List<Permission>, ObservableSource<Boolean>>{}); 復(fù)制代碼- request() 方法返回 Observable 對(duì)象
- buffer(len) 操作符將一個(gè) Observable 變換為 Observable<List>,原來的 Observable 正常發(fā)射數(shù)據(jù),變換產(chǎn)生的 Observable 發(fā)射這些數(shù)據(jù)的緩存集合。buffer 將數(shù)據(jù)緩存到一個(gè)集合當(dāng)中,然后在適當(dāng)(比如:所有請(qǐng)求的權(quán)限結(jié)果都返回了)的時(shí)機(jī)一起發(fā)送。
- flatMap() 方法將 Observable<List> 轉(zhuǎn)化為 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>>() {@Overridepublic Observable<Permission> apply(Object o) throws Exception {return requestImplementation(permissions);}});}復(fù)制代碼在 request 這個(gè)方法里面,其實(shí) oneOf() 和 pending() 方法我們可以忽略的,主要的話,我們應(yīng)該關(guān)注 requestImplementation(final String... permissions) 這個(gè)方法,在這個(gè)方法里面,主要實(shí)現(xiàn)了權(quán)限的請(qǐng)求。
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.// 權(quán)限已經(jīng)被同意或者不是 Android 6.0 以上版本,創(chuàng)建一個(gè) 同意的 Permission 對(duì)象。list.add(Observable.just(new Permission(permission, true, false)));continue;}if (isRevoked(permission)) {// 權(quán)限被拒絕,返回一個(gè) 拒絕的 Permission 對(duì)象。list.add(Observable.just(new Permission(permission, false, false)));continue;}PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);// 如果 subject 不存在,那么創(chuàng)建一個(gè) subject。if (subject == null) {unrequestedPermissions.add(permission);subject = PublishSubject.create();mRxPermissionsFragment.setSubjectForPermission(permission, subject);}list.add(subject);}// 還未提起申請(qǐng)的權(quán)限進(jìn)行申請(qǐng)if (!unrequestedPermissions.isEmpty()) {String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);requestPermissionsFromFragment(unrequestedPermissionsArray);}// 嚴(yán)格按照順序發(fā)射數(shù)據(jù)return Observable.concat(Observable.fromIterable(list));}復(fù)制代碼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 subjectPublishSubject<Permission> subject = mSubjects.get(permissions[i]);if (subject == null) {// No subject foundLog.e(RxPermissions.TAG, "RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.");return;}// 發(fā)射權(quán)限申請(qǐng)結(jié)果mSubjects.remove(permissions[i]);boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));subject.onComplete();}}復(fù)制代碼RxJava 操作符
Observable.just()
just 操作符是將一個(gè)對(duì)象轉(zhuǎn)化為 Observable 的操作符。這個(gè)對(duì)象可以是一個(gè)數(shù)字、字符串或者是數(shù)組對(duì)象等,是 RxJava 中快速創(chuàng)建一個(gè) Observable 對(duì)象的操作符。如果有 subscriber 訂閱的話,那么會(huì)依次調(diào)用 onNext() 和 OnComplete() 方法。所以這里只是創(chuàng)建了一個(gè) Observable 對(duì)象,方便后續(xù)的調(diào)用。
compose(Transformer)操作符
compose 操作符是對(duì) Observable 對(duì)象的整體轉(zhuǎn)化。例如:通過 Transformer,我們可以將 Observable 對(duì)象轉(zhuǎn)換成 Observable 對(duì)象了。
public static ObservableTransformer<String,Boolean> getTransformer(){return new ObservableTransformer<String, Boolean>() {@Overridepublic ObservableSource<Boolean> apply(Observable<String> upstream) {return upstream.flatMap(new Function<String, ObservableSource<Boolean>>() {@Overridepublic ObservableSource<Boolean> apply(String s) throws Exception {return Observable.just(true);}});}};} 復(fù)制代碼/*** 線程切換* @return*/public static <T> ObservableTransformer<T,T> getScheduler(){return new ObservableTransformer<T, T>() {@Overridepublic ObservableSource<T> apply(Observable<T> upstream) {return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());}};}復(fù)制代碼buffer 操作符
buffer 操作符將一個(gè) Observable 變換為另一個(gè),原來的 Observable 正常發(fā)射數(shù)據(jù),變換產(chǎn)生的 Observable 發(fā)射這些數(shù)據(jù)的緩存集合。buffer將數(shù)據(jù)緩存到一個(gè)集合當(dāng)中,然后在適當(dāng)?shù)臅r(shí)機(jī)一起發(fā)送。 buffer(count) 以列表(List)的形式發(fā)射非重疊的緩存,每一個(gè)緩存至多包含來自原始Observable的count項(xiàng)數(shù)據(jù)(最后發(fā)射的列表數(shù)據(jù)可能少于count項(xiàng))
- 例如:緩存 2 個(gè)數(shù)據(jù)之后,再發(fā)送數(shù)據(jù)(調(diào)用 buffer(count) 函數(shù))
- 輸出結(jié)果
- 例如:緩存 3 個(gè)數(shù)據(jù),再發(fā)送數(shù)據(jù),每次移動(dòng) 1 步
- 輸出結(jié)果
concat 操作符
是接收若干個(gè)Observables,發(fā)射數(shù)據(jù)是有序的,不會(huì)交叉。
Subject
- 作為 Observable 和 Observer 之間的橋梁
- 可以當(dāng)做 Observable
- 可以當(dāng)做 Observer
PublishSubject
繼承至 Subject,它的 Observer 只會(huì)接收到 PublishSubject 被訂閱之后發(fā)送的數(shù)據(jù)。示例代碼如下;我們只會(huì)接收到 publishSubject3 和 publishSubject4;
PublishSubject<String> publishSubject = PublishSubject.create();publishSubject.onNext("publishSubject1");publishSubject.onNext("publishSubject2");publishSubject.subscribe(new Consumer<String>() {@Overridepublic void accept(String s) throws Exception {Log.i(TAG, "accept: "+s);}});publishSubject.onNext("publishSubject3");publishSubject.onNext("publishSubject4");復(fù)制代碼- 執(zhí)行結(jié)果
舉一反三
可以看到,在 RxPermissions 這個(gè)獲取權(quán)限的開源框架中,往 Activity 中添加了一個(gè)空的 Fragment,這個(gè) fragment 才是用來發(fā)起申請(qǐng)權(quán)限和處理權(quán)限的請(qǐng)求,最后再將結(jié)果返回,這樣子就避免了我們發(fā)送請(qǐng)求之后,還需要在 onRequestPermissionsResult 中進(jìn)行處理,并判斷 requestCode 等繁瑣操作。想到這里,我們平時(shí)使用 startActivityForResult 時(shí),我們也可以同樣采用這樣的思路來簡(jiǎn)化我們的請(qǐng)求。
同樣的,我們采用添加空白的 fragment,來做 startActivityForResult 請(qǐng)求,主要的實(shí)現(xiàn)類有 SimpleForResult 和 SimpleOnResultFragment,ActivityResultInfo 是請(qǐng)求 model,接下我們先看代碼。
SimpleForResult
/*** @Author: chenjianrun* @Time: 2018/12/7* @Description: 避免調(diào)用 startActivity 時(shí),需要 onActivityResult 處理的類*/ public class SimpleForResult {private static final String TAG = "SimpleForResult";private SimpleOnResultFragment mSimpleOnResultFragment;public SimpleForResult(AppCompatActivity activity) {mSimpleOnResultFragment = getOnResultFragment(activity.getSupportFragmentManager());}public SimpleForResult(Fragment fragment){mSimpleOnResultFragment = getOnResultFragment(fragment.getChildFragmentManager());}private SimpleOnResultFragment getOnResultFragment(FragmentManager fragmentManager) {SimpleOnResultFragment simpleOnResultFragment = findSimpleOnResultFragment(fragmentManager);if (simpleOnResultFragment == null) {simpleOnResultFragment = new SimpleOnResultFragment();fragmentManager.beginTransaction().add(simpleOnResultFragment, TAG).commitAllowingStateLoss();fragmentManager.executePendingTransactions();}return simpleOnResultFragment;}private SimpleOnResultFragment findSimpleOnResultFragment(FragmentManager fragmentManager) {return (SimpleOnResultFragment) fragmentManager.findFragmentByTag(TAG);}public Observable<ActivityResultInfo> startForResult(Intent intent) {return mSimpleOnResultFragment.startForResult(intent);}public Observable<ActivityResultInfo> startForResult(Class<?> clazz) {Intent intent = new Intent(mSimpleOnResultFragment.getActivity(), clazz);return startForResult(intent);}public void startForResult(Intent intent, Callback callback) {mSimpleOnResultFragment.startForResult(intent, callback);}public void startForResult(Class<?> clazz, Callback callback) {Intent intent = new Intent(mSimpleOnResultFragment.getActivity(), clazz);startForResult(intent, callback);}public interface Callback {void onActivityResult(int requestCode, int resultCode, Intent data);} }復(fù)制代碼SimpleOnResultFragment
/*** @Author: chenjianrun* @Time: 2018/12/7* @Description: 真正調(diào)用 startActivity 和處理 onActivityResult 的類。*/ public class SimpleOnResultFragment extends Fragment {private static Map<Integer, PublishSubject<ActivityResultInfo>> mSubjects = new HashMap<>();private static Map<Integer, SimpleForResult.Callback> mCallbacks = new HashMap<>();public SimpleOnResultFragment() {}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setRetainInstance(true);}public Observable<ActivityResultInfo> startForResult(final Intent intent) {int requestCode = generateRequestCode();PublishSubject<ActivityResultInfo> subject = PublishSubject.create();mSubjects.put(requestCode, subject);startActivityForResult(intent, requestCode);return subject;}public void startForResult(Intent intent, SimpleForResult.Callback callback) {int requestCode = generateRequestCode();mCallbacks.put(requestCode, callback);startActivityForResult(intent, requestCode);}@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);//rxjava方式的處理PublishSubject<ActivityResultInfo> subject = mSubjects.remove(requestCode);if (subject != null) {subject.onNext(new ActivityResultInfo(requestCode, resultCode, data));subject.onComplete();}//callback方式的處理SimpleForResult.Callback callback = mCallbacks.remove(requestCode);if (callback != null) {callback.onActivityResult(requestCode, resultCode, data);}}private int generateRequestCode(){Random random = new Random();for (;;){int code = random.nextInt(65536);if (!mSubjects.containsKey(code) && !mCallbacks.containsKey(code)){return code;}}} } 復(fù)制代碼ActivityResultInfo
package com.luwei.util.forresult;import android.content.Intent;/*** @Author: chenjianrun* @Time: 2018/12/7* @Description:*/ public class ActivityResultInfo {private int requestCode;private int resultCode;private Intent data;public ActivityResultInfo(int requestCode, int resultCode, Intent data) {this.requestCode = requestCode;this.resultCode = resultCode;this.data = data;}public int getRequestCode() {return requestCode;}public void setRequestCode(int requestCode) {this.requestCode = requestCode;}public ActivityResultInfo(int resultCode, Intent data) {this.resultCode = resultCode;this.data = data;}public int getResultCode() {return resultCode;}public void setResultCode(int resultCode) {this.resultCode = resultCode;}public Intent getData() {return data;}public void setData(Intent data) {this.data = data;} }復(fù)制代碼簡(jiǎn)單使用示例
- 簡(jiǎn)單的 Activity 調(diào)用
- 調(diào)用攝像頭
總結(jié)
以上是生活随笔為你收集整理的RxPermissions 源码解析之举一反三的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql在线复制_mysql如何在线修
- 下一篇: 宝塔配置mysql host_阿里云安装