使用的技術(shù)
- RxJava
- Fragment
原理描述
通過(guò)向申請(qǐng)權(quán)限的Fragment 或 Activity 中添加一個(gè)沒(méi)有布局的Fragment來(lái)申請(qǐng)權(quán)限封拧,使用Fragment的相關(guān)權(quán)限申請(qǐng)方法牍帚,來(lái)申請(qǐng)權(quán)限紊馏。然后通過(guò)RxJava 的 PublishSubject 特性 將授權(quán)結(jié)果發(fā)送給申請(qǐng)的地方
1569382934(1).jpg
代碼流程
-
發(fā)起申請(qǐng)
// 申請(qǐng)者可以為 activity public RxPermissions(@NonNull final FragmentActivity activity) { mRxPermissionsFragment = getLazySingleton(activity.getSupportFragmentManager()); } // 申請(qǐng)者可以為 fragment public RxPermissions(@NonNull final Fragment fragment) { mRxPermissionsFragment = getLazySingleton(fragment.getChildFragmentManager()); }
向當(dāng)前申請(qǐng)者布局內(nèi)添加一個(gè)沒(méi)有布局的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;
}
-
遍歷授權(quán)請(qǐng)求 添加到觀察者集合中
// 返回Observable供申請(qǐng)者訂閱 @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<>(); // 使用者可能一次申請(qǐng)了多個(gè)權(quán)限叽赊,將每個(gè)權(quán)限轉(zhuǎn)換成一個(gè)權(quán)限被觀察者,然后再將這些權(quán)限被觀察者連接起來(lái) for (String permission : permissions) { mRxPermissionsFragment.get().log("Requesting permission " + permission); //已經(jīng)被授權(quán)了或者是6.0以下 則直接返回?cái)y帶true的權(quán)限被觀察者 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<Permission> subject = mRxPermissionsFragment.get().getSubjectByPermission(permission); // Create a new subject if not exists // 正常情況下這個(gè)地方的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()]); //觸發(fā)fragment 發(fā)起權(quán)限申請(qǐng)的地方 requestPermissionsFromFragment(unrequestedPermissionsArray); } // concat 為串行操作符 return Observable.concat(Observable.fromIterable(list)); }
-
無(wú)布局fragment 發(fā)起權(quán)限申請(qǐng)
/** * 開(kāi)始請(qǐng)求權(quán)限 * * @param permissions */ @TargetApi(Build.VERSION_CODES.M) void requestPermissions(@NonNull String[] permissions) { requestPermissions(permissions, PERMISSIONS_REQUEST_CODE); }
無(wú)布局fragment 處理權(quán)限 并通過(guò)PublishSubject 發(fā)送消息出去
/**
* 權(quán)限的回調(diào)
*
* 第一次請(qǐng)求權(quán)限時(shí)ActivityCompat.shouldShowRequestPermissionRationale=false;
* 第一次請(qǐng)求權(quán)限被禁止,但未選擇【不再提醒】ActivityCompat.shouldShowRequestPermissionRationale=true;
* 允許某權(quán)限后ActivityCompat.shouldShowRequestPermissionRationale=false;
* 禁止權(quán)限碾局,并選中【禁止后不再詢問(wèn)】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 所申請(qǐng)的權(quán)限
* @param grantResults 拒絕與否的數(shù)組
* @param shouldShowRequestPermissionRationale 是否需要顯示申請(qǐng)理由的數(shù)組
*/
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;
}
//將數(shù)據(jù)結(jié)果一個(gè)個(gè)發(fā)到下游
mSubjects.remove(permissions[i]);
boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));
subject.onComplete();
}
}
最后感想
整體庫(kù)的代碼比較簡(jiǎn)單奴艾,但是為我們提供了一些解決問(wèn)題的思路
① 對(duì)于需要生命周期感知的問(wèn)題净当,我們可以委托一個(gè)fragment來(lái)進(jìn)行管理
② 使用PublishSubject 能夠輕松實(shí)現(xiàn)一些基于觀察者模式的需求