??Android 6.0權(quán)限管理的接入方式有點(diǎn)累蕾羊,這模式跟
ActivityResult
一樣的實(shí)現(xiàn)方式恬叹,請(qǐng)求和接收是分離的澜倦,沒有掛回調(diào)函數(shù)那么方便股冗,當(dāng)頁(yè)面代碼量大的時(shí)候閱讀性不好:
private void requestPermission(){
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
??因?yàn)楦鶤ctvitiyResult一個(gè)模式翅阵,請(qǐng)求返回結(jié)果是以數(shù)組方式提供的, 想知道所有結(jié)果是否都grant得要遍歷數(shù)組一一比較grantResults惠勒,想知道究竟哪個(gè)權(quán)限被拒絕角钩,也要遍歷permissions并判斷同樣index對(duì)應(yīng)的grantResults結(jié)果吝沫。
??其實(shí),因?yàn)闃I(yè)務(wù)代碼比較多递礼,大家想擁有的請(qǐng)求權(quán)限的API如下那么簡(jiǎn)單:
// 只關(guān)注全部授權(quán)通過
requestPermission(new OnGrantResult() {
@Override
public void onGrant() {
// do something when grant
}
@Override
public void onDenied() {
// do something when denied
}
}, Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_PHONE_STATE);
// 關(guān)注個(gè)別權(quán)限授權(quán)結(jié)果
requestEachPermission(new OnEachGrantResult() {
@Override
public void onNext(Permission permission) {
// check someone permission and
// its grant state and do something you want
}
}, Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_PHONE_STATE);
說到封裝惨险,如上API,可能很多人感覺不難脊髓,可能很多人都想到的辦法是:
- 改BaseActivity和BaseFragment并在其中添加新的API:
requestPermissions(OnGrantResult result, String... permissions)
辫愉。 - 然后在BaseActivity和BaseFragment 復(fù)寫 onRequestPermissionsResult(), 并在其中遍歷grantResults數(shù)組,只有全部都等于PackageManager.PERMISSION_GRANTED則最終通過request在map中找到OnGrantResult觸發(fā)回調(diào)以此告知子Activity或者Fragment是全部授權(quán)成功的将硝,否則授權(quán)失敗恭朗。
??看似完美,但是有一個(gè)最大的問題是代碼嵌入性太強(qiáng)依疼,BaseActivity和BaseFragment實(shí)在太臃腫痰腮,一有類似的功能增加就想動(dòng)它們,可能有些朋友認(rèn)為律罢,BaseActivity或者BaseFragment可以搞多層繼承啊膀值,這樣每一層只做對(duì)應(yīng)的事情,比如把權(quán)限相關(guān)的封裝在一個(gè)BasePermissionActivity里误辑,然后BaseActivity繼承BasePermissionActivity里沧踏,可是時(shí)間長(zhǎng)了你會(huì)發(fā)現(xiàn)BaseActivity的搞了很多層,一有新功能就加層級(jí)稀余,說實(shí)話層級(jí)依賴不如扁平依賴。
??前段時(shí)間在看RxJava原理的時(shí)候順便看到了衍生作品RxPermission趋翻,發(fā)現(xiàn)它非常奇妙睛琳,通過RxPermission請(qǐng)求權(quán)限無需改變BaseActivity又能以掛回調(diào)方式接收請(qǐng)求結(jié)果盒蟆,想看究竟內(nèi)部是怎么做到的。
??看完之后的感慨是:好吧师骗,RxJava的確很強(qiáng)大历等,不過RxPermission里的Rx只是一個(gè)障眼法,本質(zhì)原理是在需要請(qǐng)求權(quán)限的Activity打開一個(gè)無UI的Fragment或者在需要請(qǐng)求權(quán)限的Fragment里打開一個(gè)無UI的Child Fragment辟癌,并在打開的Fragment里請(qǐng)求權(quán)限寒屯,因?yàn)镕ragment和它的宿主天生能進(jìn)行通信,所以在無UI的Fragment里請(qǐng)求權(quán)限并把授權(quán)結(jié)果告知它宿主即需要權(quán)限的Activity或者Fragment黍少。
??知道這個(gè)原理后寡夹,如果不希望在自己項(xiàng)目中引入RxJava你就可以自己簡(jiǎn)化RxPermission了,其實(shí)很簡(jiǎn)單厂置,保留一個(gè)用于權(quán)限請(qǐng)求的fragment和權(quán)限請(qǐng)求器之間的callback即可菩掏。
簡(jiǎn)化后的使用如下:
public class MainActivity extends AppCompatActivity {
private Permissions mPermissions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// init permissions
mPermissions = new Permissions(this);
Button requestBtn = findViewById(R.id.requestBtn);
requestBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPermissions.request(new OnGrantResult() {
@Override
public void onGrant() {
// do something when grant
}
@Override
public void onDenied() {
// do something when denied
}
}, Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_PHONE_STATE);
}
});
Button requestEachBtn = findViewById(R.id.requestEachBtn);
requestEachBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPermissions.requestEach(new OnEachGrantResult() {
@Override
public void onNext(Permission permission) {
// check someone permission and
// its grant state and do something you want
}
}, Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_PHONE_STATE);
}
});
}
}
詳細(xì)實(shí)現(xiàn)可以參考這里,同樣的原理也實(shí)現(xiàn)了以掛回調(diào)方式接收startActivityForResult()的結(jié)果昵济,又同時(shí)簡(jiǎn)化了以前的一篇文章介紹的打開頁(yè)面自動(dòng)登錄并回來-攔截器(升級(jí)版)智绸,有一種觸類旁通的感覺。