本文是《Android開發(fā)之深度項目設計探索》系列的第三篇滑燃,主要介紹的是 基于最新RxPermissions 類庫的使用及源碼分析拱雏,本系列歷史文章:
《Android開發(fā)之深度項目設計探索(一)》
《Android開發(fā)之深度項目設計探索(二)》
Permission屏歹,這個單詞翻譯過來的意思有:允許狡相、許可准颓、權限镣屹。我們Android開發(fā)親切的將其稱為權限序芦。
權限是一種安全機制戚哎。Android權限機制主要用于:限制應用程序內(nèi)部某些具有限制特性的功能使用以及應用程序之間的組件訪問亡资。
在Android系統(tǒng)6.0版本(也就是 SdkVersion = 23)之前,權限的聲明僅需要在清單配置文件中板驳,通過標簽uses-permission來聲明應用,也就意味所需要的權限碍拆,如:
<uses-permission android:name="android.permission.CAMERA"/>
這行配置代碼的意思意味著該應用允許使用CAMERA(照相機)權限若治;
由于時代的發(fā)展以及各種因素慨蓝,谷歌Android技術團隊出于安全角度這一原則設計考慮,在Android系統(tǒng)6.0版本開始直砂,之后的版本提出了一些新概念菌仁,整理下來有以下幾點:
概念一:權限分為兩種、一種是普通權限静暂;還有一種是危險權限
概念二:普通權限济丘,直接在清單文件中配置聲明即可
概念三:危險權限,谷歌覺得部分權限涉及到用戶的隱私洽蛀,因此必須明確告知用戶應用需要那些權限摹迷,但是這樣的危險權限需要用戶手動授權
既然谷歌在新版本給我們帶來了新概念和需要解決的問題,那么就需要解決這個權限問題:
- 解決方式一:暫時不適配Android6.0系統(tǒng)版本郊供,也就是將targetSdkVersion降到23以上(這種法子算曲線救國)
- 解決方式二:直接適配危險權限峡碉,主動告知用戶打開權限
那么這篇文章介紹的 RxPermissions-官方文檔,這是一款基于Rxjava2的運行時權限解決方案驮审,
- 這個庫的minSdkVersion 最低不能低于11鲫寄,也就是 "use this library your minSdkVersion must be >= 11"
- 添加Maven支持
allprojects {
repositories {
...
//添加如下支持
maven { url 'https://jitpack.io' }
}
}
- 在gradle導入最新版本的RxPermissions依賴:
implementation 'com.github.tbruyelle:rxpermissions:0.10.2
集成和使用步驟如下:
- 首先:創(chuàng)建RxPermissions實例:
//這里的this就是Activity or Fragment instance
RxPermissions rxPermissions = new RxPermissions(this);
- 接著:代碼使用,需搭配Rxjava2使用疯淫,寫法如下:
A:獲取單個權限
RxPermissions rxPermissions = new RxPermissions(this);
// 申請單個權限
rxPermissions.request(Manifest.permission.CAMERA).subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if (aBoolean == true){
// 用戶已經(jīng)同意該權限
Log.i(TAG, "accept: CAMERA 權限成功");
}else {
// 用戶拒絕權限
Log.i(TAG, "accept: CAMERA 權限失敗");
}
}
});
B:獲取多個權限
獲取多個權限方式有兩種寫法:
- 寫法一:
// 用戶同時申請多個權限地来,方式一:
// 如果用戶全部申請成功,才會返回true
// 如果用戶有一個權限拒絕申請熙掺,那么就會返回失敗
rxPermissions.requestEach(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_CALENDAR,
Manifest.permission.READ_PHONE_STATE).
subscribe(new Consumer<Permission>() {
@Override
public void accept(Permission permission) throws Exception {
if (permission.granted) {
// 用戶已經(jīng)同意該權限
Log.d(TAG, permission.name + "用戶授予權限");
} else if (permission.shouldShowRequestPermissionRationale) {
// 用戶拒絕了該權限未斑,沒有選中『不再詢問』(Never ask again),那么下次再次啟動時,還會提示請求權限的對話框
Log.d(TAG, permission.name + "用戶拒絕權限——下次啟動可以繼續(xù)申請");
} else {
// 1壹ā@唷!注意@铝汀Q客弧!
// 用戶拒絕了該權限费就,并且選中了『不再詢問』
// 需要去 APP設置 里面去打開對應的申請權限
Log.d(TAG, permission.name + "用戶拒絕權限——勾選了不在詢問——提示用戶后續(xù)去手動申請");
}
}
});
- 寫法二:
// 用戶同時申請多個權限诉瓦,方式二:
// 對應每個權限申請的操作
// 思考:
// 我們可以在應用啟動之前也打開獲取權限,然后記錄每個權限是否申請成功力细,記錄的方式可以通過sp存儲狀態(tài)
// 在需要權限的時候睬澡,首先判斷SP存儲的狀態(tài)是否為權限授權成功,如果沒有授權成功眠蚂,那么就再次請求授權
rxPermissions.requestEachCombined(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_CALENDAR,
Manifest.permission.READ_PHONE_STATE).
subscribe(new Consumer<Permission>() {
@Override
public void accept(Permission permission) throws Exception {
// 判斷具體的對應權限
if (permission.name.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
if (permission.granted){
Log.i(TAG, "WRITE_EXTERNAL_STORAGE_accept: 權限申請成功");
}else {
Log.i(TAG, "WRITE_EXTERNAL_STORAGE_accept: 權限授權失敗");
}
}
if (permission.name.equals(Manifest.permission.READ_PHONE_STATE)) {
if (permission.granted){
Log.i(TAG, "READ_PHONE_STATE: 權限申請成功");
}else {
Log.i(TAG, "READ_PHONE_STATE: 權限授權失敗");
}
}
}
});
嗯煞聪,沒錯,基本上逝慧,這款框架的使用就已經(jīng)介紹完了昔脯,是不是很簡單優(yōu)雅啄糙。
但是有一些細節(jié)我們需要注意,如該庫的作者不建議我們在 onResume()這個生命周期里面進行申請權限云稚, RxPermissions-官方文檔 也給了詳細說明隧饼,
下面是源碼解讀
Rxpermissions源碼分析:
使用一:
我們知道,Rxpermissions使用的第一步是在Activity中創(chuàng)建RxPermissions這個實例化對象静陈。實際上燕雁,RxPermission采用的方式是利用了一個隱形的Fragment來請求權限,然后在回調(diào)中用RxJava進行數(shù)據(jù)的組裝和轉化鲸拥,最后變成了布爾類型的數(shù)據(jù)回調(diào)回來拐格。這個隱形的Fragment,就是類庫中的RxPermissionsFragment刑赶,
public class RxPermissionsFragment extends Fragment {
private static final int PERMISSIONS_REQUEST_CODE = 42;
// Contains all the current permission requests.
// Once granted or denied, they are removed from it.
private Map<String, PublishSubject<Permission>> mSubjects = new HashMap<>();
private boolean mLogging;
public RxPermissionsFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@TargetApi(Build.VERSION_CODES.M)
void requestPermissions(@NonNull String[] permissions) {
requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);
}
@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();
}
}
@TargetApi(Build.VERSION_CODES.M)
boolean isGranted(String permission) {
final FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity == null) {
throw new IllegalStateException("This fragment must be attached to an activity.");
}
return fragmentActivity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
@TargetApi(Build.VERSION_CODES.M)
boolean isRevoked(String permission) {
final FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity == null) {
throw new IllegalStateException("This fragment must be attached to an activity.");
}
return fragmentActivity.getPackageManager().isPermissionRevokedByPolicy(permission, getActivity().getPackageName());
}
public void setLogging(boolean logging) {
mLogging = logging;
}
public PublishSubject<Permission> getSubjectByPermission(@NonNull String permission) {
return mSubjects.get(permission);
}
public boolean containsByPermission(@NonNull String permission) {
return mSubjects.containsKey(permission);
}
public void setSubjectForPermission(@NonNull String permission, @NonNull PublishSubject<Permission> subject) {
mSubjects.put(permission, subject);
}
void log(String message) {
if (mLogging) {
Log.d(RxPermissions.TAG, message);
}
}
}
可以看到捏浊,這個類繼承了Fragment。然后在onCreate中并沒有創(chuàng)建具體的UI布局撞叨,我們知道金踪。Fragment具有屬性retainInstance,默認值為false牵敷。 當設備旋轉時热康,fragment會隨托管activity一起銷毀并重建。解決辦法是:調(diào)用setRetainInstance(true)方法可保留fragment不會重新創(chuàng)建(例如旋轉屏幕)
你可能會問劣领,那這個隱形的Fragment又是在那里創(chuàng)建的?答案:創(chuàng)建的時機铁材,是在創(chuàng)建RxPermissions的對象中尖淘,順帶創(chuàng)建了這個實例對象(通過構造方法實現(xiàn)):下面是Rxpermissions這個類的構造方法以及部分函數(shù)源碼:
public class RxPermissions {
static final String TAG = RxPermissions.class.getSimpleName();
static final Object TRIGGER = new Object();
@VisibleForTesting
Lazy<RxPermissionsFragment> mRxPermissionsFragment;
public RxPermissions(@NonNull final FragmentActivity activity) {
mRxPermissionsFragment = getLazySingleton(activity.getSupportFragmentManager());
}
public RxPermissions(@NonNull final Fragment fragment) {
mRxPermissionsFragment = getLazySingleton(fragment.getChildFragmentManager());
}
@NonNull
private Lazy<RxPermissionsFragment> getLazySingleton(@NonNull final FragmentManager fragmentManager) {
return new Lazy<RxPermissionsFragment>() {
private RxPermissionsFragment rxPermissionsFragment;
@Override
public synchronized RxPermissionsFragment get() {
if (rxPermissionsFragment == null) {
rxPermissionsFragment = getRxPermissionsFragment(fragmentManager);
}
return rxPermissionsFragment;
}
};
}
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;
}
//.............省略部分源碼................
}
這個隱形的Fragment很重要,因為權限的申請與申請結果的回調(diào)都是在Fragment中完成的著觉〈迳基于此,開發(fā)人員才不需要為申請結果重寫回調(diào)方法饼丘。
使用二:
接著趁桃,是Rxpermissions基本使用的代碼,也就是rxPermissions.request......肄鸽,對應的源碼如下:
/**
* 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));
}
從中可以看到卫病,上面使用的三種寫法,最終是調(diào)到了
Observable.just(TRIGGER).compose(ensureEach(permissions));
- 步驟一:
這里的 Just 操作符典徘,簡單點理解就是可以將某個對象轉化為Observable對象蟀苛。Just操作符,是RxJava中非炒澹快捷的創(chuàng)建Observable對象的方法帜平。如果通過just操作符創(chuàng)建了一個Observable幽告,繼續(xù)使用subscriber訂閱則會依次調(diào)用其onNext()和onCompleted()方法。這里的TRIGGER裆甩,源碼里面就是一個Object對象冗锁。
static final Object TRIGGER = new Object();
通過源碼可以看到,根據(jù)just操作符創(chuàng)建完Observable對象之后緊接著調(diào)用了compose()方法嗤栓。
compose()操作符主要是將一個Observable對象(具體的數(shù)據(jù)類型)轉換成另一個Observable(對應的數(shù)據(jù)類型)對象冻河,我們發(fā)現(xiàn)此方法最終調(diào)用的是ensure(permissions)這個方法
- 步驟二:
ensure(permissions)這個方法的源碼如下:
public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
ObservableTransformer<T, Boolean> observableTransformer = new ObservableTransformer<T, Boolean>() {
@Override
public ObservableSource<Boolean> apply(Observable<T> o) {
Observable<Boolean> booleanObservable = request(o, permissions)
// Transform Observable<Permission> to Observable<Boolean>
.buffer(permissions.length)
.flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(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);
}
});
return booleanObservable;
}
};
return observableTransformer;
}
這個buffer()的操作符作用是什么呢,它的作用是為了將一個序列的Observable<Permission>對象轉換成Observable<List<Permission>>對象抛腕,
拋開Rxjava2常規(guī)的操作符除外芋绸,首先看下這段來自RxPermissions類庫部分源碼提供的自定義方法有:request(o, permissions);源碼還自定義了一個類:Permission担敌,其中p.granted這種寫法貌似就是類名.成員變量的操作摔敛,那我們就先看一眼Permission這個最基本的Java類
Permission源碼如下:
public class Permission {
public final String name;
public final boolean granted;
public final boolean shouldShowRequestPermissionRationale;
public Permission(String name, boolean granted) {
this(name, granted, false);
}
public Permission(String name, boolean granted, boolean shouldShowRequestPermissionRationale) {
this.name = name;
this.granted = granted;
this.shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale;
}
public Permission(List<Permission> permissions) {
name = combineName(permissions);
granted = combineGranted(permissions);
shouldShowRequestPermissionRationale = combineShouldShowRequestPermissionRationale(permissions);
}
@Override
@SuppressWarnings("SimplifiableIfStatement")
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Permission that = (Permission) o;
if (granted != that.granted) return false;
if (shouldShowRequestPermissionRationale != that.shouldShowRequestPermissionRationale)
return false;
return name.equals(that.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + (granted ? 1 : 0);
result = 31 * result + (shouldShowRequestPermissionRationale ? 1 : 0);
return result;
}
@Override
public String toString() {
return "Permission{" +
"name='" + name + '\'' +
", granted=" + granted +
", shouldShowRequestPermissionRationale=" + shouldShowRequestPermissionRationale +
'}';
}
private String combineName(List<Permission> permissions) {
return Observable.fromIterable(permissions)
.map(new Function<Permission, String>() {
@Override
public String apply(Permission permission) throws Exception {
return permission.name;
}
}).collectInto(new StringBuilder(), new BiConsumer<StringBuilder, String>() {
@Override
public void accept(StringBuilder s, String s2) throws Exception {
if (s.length() == 0) {
s.append(s2);
} else {
s.append(", ").append(s2);
}
}
}).blockingGet().toString();
}
private Boolean combineGranted(List<Permission> permissions) {
return Observable.fromIterable(permissions)
.all(new Predicate<Permission>() {
@Override
public boolean test(Permission permission) throws Exception {
return permission.granted;
}
}).blockingGet();
}
private Boolean combineShouldShowRequestPermissionRationale(List<Permission> permissions) {
return Observable.fromIterable(permissions)
.any(new Predicate<Permission>() {
@Override
public boolean test(Permission permission) throws Exception {
return permission.shouldShowRequestPermissionRationale;
}
}).blockingGet();
}
}
這個類我們先放在這里,在看一眼類庫自定義的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");
}
Observable<Permission> permissionObservable =
oneOf(trigger, pending(permissions))
.flatMap(new Function<Object, Observable<Permission>>() {
@Override
public Observable<Permission> apply(Object o) {
return requestImplementation(permissions);
}
});
return permissionObservable;
}
可以看到這個方法返回的對象是一個Observable< Permission >全封,內(nèi)部邏輯首先判斷permissions 是否為null马昙,長度是否大于0,如果滿足其中一個條件就拋異常刹悴;如果permissions 不為null行楞,長度且大于0,在調(diào)用oneOf方法和pending( )方法來創(chuàng)建合并Observable對象土匀。其中子房,oneOf()和pending( )方法的函數(shù)如下:
private Observable<?> oneOf(Observable<?> trigger, Observable<?> pending) {
if (trigger == null) {
return Observable.just(TRIGGER);
}
return Observable.merge(trigger, pending);
}
private Observable<?> pending(final String... permissions) {
for (String p : permissions) {
if (!mRxPermissionsFragment.get().containsByPermission(p)) {
return Observable.empty();
}
}
return Observable.just(TRIGGER);
}
pending(final String... permissions)這個函數(shù)的主要功能有:
- 首先循環(huán)遍歷,查詢該權限是否已經(jīng)在申請過了
- 如果列表中有一個權限沒有在RxPermissionsFragment的HashMap集合中保存就轧,
就返回Observeble.empty()证杭,返回的這個Observable對象會調(diào)用onComplete()方法,所以并不會進入flatMap
oneOf(Observable<?> trigger, Observable<?> pending)這個函數(shù)的主要是:
- 首先判斷trigger對象是否為null妒御,如果為空解愤,則通過Just操作符創(chuàng)建一個Observable
- 最后返回合并的Observable對象。
我們知道乎莉,request(o, permissions)最終是調(diào)用了requestImplementation(permissions);這個方法送讲,下面就看下requestImplementation(permissions);方法的內(nèi)部源碼:
@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.get().log("Requesting permission " + permission);
if (isGranted(permission)) {
// Already granted, or not Android M
// Return a granted Permission object.
list.add(Observable.just(new Permission(permission, true, false)));
continue;
}
if (isRevoked(permission)) {
// Revoked by a policy, return a denied Permission object.
list.add(Observable.just(new Permission(permission, false, false)));
continue;
}
PublishSubject<Permission> subject = mRxPermissionsFragment.get().getSubjectByPermission(permission);
// Create a new subject if not exists
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()]);
requestPermissionsFromFragment(unrequestedPermissionsArray);
}
return Observable.concat(Observable.fromIterable(list));
}
這段代碼的主要意思有以下幾個方面(按照順序):
A:創(chuàng)建第一個集合(也就是源碼的List<Observable<Permission>> list)保存已經(jīng)申請的權限
B:創(chuàng)建第二個集合(也就是List<String> unrequestedPermissions)用來保存沒有請求成功的權限
C:對具體申請的權限列表進行循環(huán)遍歷:
- 如果權限已經(jīng)申請過了,則直接保存到集合中(if (isGranted(permission)) {...})
- 如果權限被撤銷惋啃,則將其作為申請被拒絕的權限保存到集合中:if (isRevoked(permission)) {...}
D:在RxPermissionsFragment中哼鬓,尋找是否已經(jīng)存在對應的權限,如果不存在(subject == null)边灭,則創(chuàng)建PublishSubject對象魄宏,將其添加到unrequestedPermissions集合中,然后將subject對象保存在第一個集合中存筏,
E:如果有未申請的權限宠互,則進行權限的申請操作味榛,也就是requestPermissionsFromFragment(unrequestedPermissionsArray);這個函數(shù)
F:利用第一個集合創(chuàng)建Observable對象,用concat操作符進行鏈接予跌,最終返回一個Observable<Permission>對象
結論:
這個方法主要的操作就是搏色,定義集合保存一次申請的所有權限。無論這個權限是已經(jīng)申請券册,還是被撤銷频轿,還是未申請,最終都會保存到list這個集合中烁焙。在后續(xù)的操作中航邢,才可以進行轉換。
同時骄蝇,定義集合用于保存未申請的權限膳殷,然后在循環(huán)結束之后進行未申請權限的申請九火。
因此,現(xiàn)在的關鍵就是requestPermissionsFromFragment(unrequestedPermissionsArray);這個函數(shù)岔激,源碼繼續(xù)跟進:
@TargetApi(Build.VERSION_CODES.M)
void requestPermissionsFromFragment(String[] permissions) {
mRxPermissionsFragment.get().log("requestPermissionsFromFragment " + TextUtils.join(", ", permissions));
mRxPermissionsFragment.get().requestPermissions(permissions);
}
繼續(xù)跟進:
@TargetApi(Build.VERSION_CODES.M)
void requestPermissions(@NonNull String[] permissions) {
requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);
}
看到這里,最終是調(diào)用了requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);辱匿,這個PERMISSIONS_REQUEST_CODE,的值是42炫彩,源碼里面有掀鹅。這個方法是Fragment提供的系統(tǒng)方法,那么回調(diào)的處理結果理所當然在RxPermissionsFragment中:
@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();
}
}
這段回調(diào)處理的源碼意思主要有:
A:首先判斷請求碼媒楼,如果請求碼不等于42,則直接返回
B:以權限列表的長度為size戚丸,創(chuàng)建一個boolean數(shù)組
C:循環(huán)遍歷划址,看權限是否被永久拒絕了。這里會調(diào)用Fragment中的shouldShowRequestPermissionRationale()方法限府。這個方法如果權限申請成功會返回true夺颤;用戶點擊了不在提醒,且拒絕權限時胁勺,會返回false世澜。
D:調(diào)用下面的重載方法
進入重載方法以后的操作有:
A:對權限列表進行循環(huán)操作。尋找相對應的:subject署穗,也就是( PublishSubject<Permission> subject = mSubjects.get(permissions[i]);)
B:如果沒有對應的subject寥裂,則直接返回
C:如果有對應的subject嵌洼,首先將集合中的permission的PublishSubject對象進行移除;接著判斷是否申請成功封恰;最后執(zhí)行onNext( )返回相應的Permission對象
基本的源碼分析就到這了麻养。
評語:可以看到,RxPermissions這個庫的主要邏輯就是在通過隱形的Fragment以及Rxjava2的操作符來進行實踐的诺舔,通過合理搭配才讓這個庫使用起來比較方便鳖昌。
如果這篇文章對您有開發(fā)or學習上的些許幫助,希望各位看官留下寶貴的star低飒,謝謝许昨。
Ps:著作權歸作者所有,轉載請注明作者, 商業(yè)轉載請聯(lián)系作者獲得授權,非商業(yè)轉載請注明出處(開頭或結尾請?zhí)砑愚D載出處褥赊,添加原文url地址),文章請勿濫用,也希望大家尊重筆者的勞動成果糕档。