您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 Code iProcess 课程 认证 咨询 工具 火云堂 讲座吧   成长之路  
会员   
 
   
 
  
每天15篇文章
不仅获得谋生技能
更可以追随信仰
 
 
     
   
 订阅
  捐助
使用RxJava处理Android 6.0运行时动态权限获取
 
 来源:CSDN  发布于 2016-4-20
5392 次浏览     评价:      
 

1.简介

RxPermissions是基于RxJava开发的用于帮助在Android 6.0中处理运行时权限检测的框架。在Android 6.0中,系统新增了部分权限的运行时动态获取。而不再是在以前的版本中安装的时候授予权限。

对于运行时的权限获取提示,国内的Android工程师们应该并不陌生,国内的第三方ROM例如MIUI在很早前就做了类似的功能。但是第三方ROM并不能提供给我们权限请求成功或失败的接口,这就导致我们无法通过PackageManager提供的checkPermission()方法来准确的获取到我们是否获得该权限。只能根据具体的权限来做相应的处理。但是在Android 6.0中我们可以准确的获取我们的应用是否获取某个权限,具体的方法希望大家看这篇文章:Android 6.0 运行时权限处理。大致方法是通过API 23中的Activity的requestPermissions(String[] permissions, int requestCode);方法请求权限,并在onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults)回调方法中处理请求结果。这个方法与onActivityResult()类似。RxPermissions在这个基础上做了封装,使我们在处理运行时权限变得更加的简单。

另外关于RxJava如果你现在还没了解过RxJava可以直接翻到文章最下面去查看我总结的一些RxJava相关的文章,不然并不推荐直接看这篇文章。下面我们就来具体看看RxPermissions的使用方法以及源码分析。

2.使用方法

1.直接获取权限(使用Retrolambda使代码更加简洁,当然并不是必须使用):

// 必须在初始化阶段调用,例如onCreate()方法中  RxPermissions.getInstance(this)    
  .request(Manifest.permission.CAMERA)      
.subscribe(granted -> {         
 if (granted) { // 在android 6.0之前会默认返回true          
   // 已经获取权限        
  } else {           
  // 未获取权限        
  }      });

2.通过条件触发获取权限(结合RxBinding使用)

// 必须在初始化阶段调用,例如onCreate()方法中 
 RxView.clicks(findViewById(R.id.enableCamera))     
 .compose(RxPermissions.getInstance(this).ensure(Manifest.permission.CAMERA))   
   .subscribe(granted -> {        
  // 当R.id.enableCamera被点击的时候触发获取权限      });

3.一次请求多个权限(有两种方式)

如果同时请求多个权限,下面这种方式会合并请求结果,即所有权限请求成功会返回true,若有一个权限未成功则返回false。

RxPermissions.getInstance(this)     
.request(Manifest.permission.CAMERA,       
 Manifest.permission.READ_PHONE_STATE)      
.subscribe(granted -> {          
if (granted) {            
 // 所有权限请求被同意        
  } else {            
 // 至少有一个权限没同意        
  }      });

当然你可以通过requestEach or ensureEach 来分别获取每一个权限请求的结果。

RxPermissions.getInstance(this)      
.requestEach(Manifest.permission.CAMERA,             
  Manifest.permission.READ_PHONE_STATE)      
.subscribe(permission -> { // 会发送两个Permission对象        
  if (permission.granted) {            
 // `permission.name` is granted !          
}      });

注意:由于在请求权限的过程中app有可能会被重启,所以权限请求必须放在初始化的阶段,比如在Activity.onCreate/onResume, 或者 
View.onFinishInflate方法中。如果不这样处理,那么如果app在请求过程中重启的话,权限请求结果将不会发送给订阅者即subscriber。

2.整体介绍

RxPermission一共就只有三个类:Permission是定义的权限model类,用来存放权限名称以及是否获取权限的信息。RxPermissions就是最主要的类了,利用RxJava提供了我们上面在使用方法中介绍的所有方法。还有一个ShadowActivity类是用来请求权限用的。下面我们就来详细介绍RxPermission的实现。

注意:如果你还未了解过RxJava那么可以先阅读本文最后的一系列优秀文章。如果你已经了解过RxJava的话,那么下面我将会介绍RxJava中的部分操作符在RxPermission中的实际运用。相信能帮助你更好的理解RxJava中操作符的使用。

3.源码分析

我们依然按照我们惯用的方法来分析,通过使用方法来分析调用流程,最终理解整个项目。首先再回顾一遍使用方法(注意这里我同时请求了两个权限),那么结果将是如果所有权限请求成功会返回true,若有一个权限未成功则返回false。代码如下:

// 必须在初始化阶段调用,例如onCreate()方法中  
RxPermissions.getInstance(this)      
.request(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)      
.subscribe(granted -> {         
 if (granted) { // 在android 6.0之前会默认返回true            
 // 已经获取权限         
 } else {             
// 未获取权限          
}      });

1.RxPermissions.getInstance(this)的实现

static RxPermissions sSingleton;      
private Context :;       
 public static RxPermissions getInstance(Context) {          
if (sSingleton == null) {             
 sSingleton = new RxPermissions(ctx.getApplicationContext());          
}         
 return sSingleton;      
}        
RxPermissions(Context ctx) {         
 mCtx = ctx;      
}

很明显是维护RxPermissions的单例,不再多做介绍,紧接着我们来看RxPermissions中request(Manifest.permission.CAMERA)方法的实现:

2.request(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)的实现:

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

首先从返回值看到是返回一个Observable<Boolean>对象,方法中也是直接return了Observable.just(null).compose(ensure(permissions))。这里涉及两个方法分别是just()以及compose()我们先解释这两个操作符:

1.Observable.just(null)

just操作符可以将某个对象转化为Observable对象,并且将其发射出去,可以是一个数字、一个字符串、数组、Iterate对象等,是RxJava中非常快捷的创建Observable对象的方法。在这里just()方法中虽然传入的是null但是并不影响创建出的Observable的作用,如果有subscriber订阅依然会依次调用其onNext()和onCompleted()方法。所以这里就是为了创建出一个Observable对象,便于后续的处理。创建完Observable对象之后紧接着调用了compose()方法:

2.compose(Transformer)操作符

compose()操作符是针对Observable自身的变换,通过我们自己定义的Transformer对象可以将对Observable对象变换的操作封装起来,实现一个简单的Transformer对象如下:

 class myTransformer implements Observable.Transformer<Object, Boolean> {           
 @Override          
public Observable<Boolean> call(Observable<Object> objectObservable) {             
 return objectObservable.map(new Func1<Object, Boolean>() {                 
 @Override                 
 public Boolean call(Object o) {                     
 return true;                  }             
 });          
}     
 }

通过上面这个Transformer就可以将任何Observable<Object>对象转换成Observable<Boolean>对象了。当然在Transformer里你也可以返回一个全新的Observable对象。RxPermissions就是这样做的,那么回到项目中再来看compose(ensure(permissions));那么ensure(permissions);一定是返回一个Transformer对象了。

3.ensure(permissions);方法的实现

我们来看看ensure(permissions)方法的实现:

public Observable.Transformer<Object, Boolean> ensure(final String... permissions) {          
//创建一个Transformer对象返回         
 return new Observable.Transformer<Object, Boolean>() {             
 // o表示当前Observable对象。              
@Override              
public Observable<Boolean> call(Observable<Object> o) {                 
 //request(o, permissions) 方法返回 Observable<Permission>对象                  
return request(o, permissions)                          
// 将Observable<Permission>转换为Observable<Boolean>                          
// buffer操作符                          
.buffer(permissions.length)                          
// flatMap操作符                          
.flatMap(new Func1<List<Permission>, Observable<Boolean>>() {                             
 @Override                             
 public Observable<Boolean> call(List<Permission> permissions) {                                  
// 如果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();                                  }                                  
// 遍历所有Permission,如果有一个未成功则返回false,全部成功返回true。                                 
 for (Permission p : permissions) {                                     
 if (!p.granted) {                                         
 return Observable.just(false);                                     
 }                                
  }                                 
 return Observable.just(true);                              
}                         
 });             
 }        
  };    
  }

确实是返回一个Observable.Transformer对象,那么在call()方法里首先调用了request(o, permissions)方法,然后又进行了buffer()和flatMap()的处理,最终会返回Observable.empty();、Observable.just(false);或Observable.just(true);对象。我们先来看看request(o, permissions)方法的实现:

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

首先对permissions做了判断,然后调用了oneOf(trigger, pending(permissions))方法,并通过flatMap()操作符在call()方法中调用了request_(permissions);按照惯例我们应该去看oneOf()方法的实现了。但是oneOf()方法里其实并没有什么实际意义,看了项目的commit log我觉得应该是历史遗留问题,作者可能是想处理一些相同重复的权限请求,但是并没有实现。所以其实这个方法完全可以这样代替;

 private Observable<Permission> request(final Observable<?> trigger,                                            
 final String... permissions) {        
 return request_(permissions);      
}

直接调用request_(permissions);即可。我测试中并没有发现问题。目前我还没有联系到作者询问这个方法的实现目的,稍后可能会提一个issue,如果有结果会在文章中更新。所以这里大家就完全可以理解成直接调用了request_(permissions);方法:

5.request_(permissions);方法的实现

 @TargetApi(Build.VERSION_CODES.M)
    private Observable request_(final String... permissions) {

        //创建出一个存放Observable的list
        List> list = new ArrayList<>(permissions.length);
        //存放还为请求权限的list
        List unrequestedPermissions = new ArrayList<>();

        // 在请求多个权限的时候,我们为每一个请求的权限都创建一个observable对象,在最后
        // 这些observable会被合并成一个response。
        for (String permission : permissions) {
            log("Requesting permission " + permission);
            //如果是已经获得的权限,或者Android版本在6.0之前则直接添加一个
            // Observable.just(new Permission(permission, true))对象.
            if (isGranted(permission)) {
                // Already granted, or not Android M
                // Return a granted Permission object.
                list.add(Observable.just(new Permission(permission, true)));
                continue;
            }
            // 如果是已经拒绝的权限则添加
            // Observable.just(new Permission(permission, false))对象.
            if (isRevoked(permission)) {
                // Revoked by a policy, return a denied Permission object.
                list.add(Observable.just(new Permission(permission, false)));
                continue;
            }

            PublishSubject subject = mSubjects.get(permission);
            // 如果mSubjects 不存在当前 permission,则添加到unrequestedPermissions中
            // 并且创建PublishSubject对象并添加到mSubjects中。
            if (subject == null) {
                unrequestedPermissions.add(permission);
                subject = PublishSubject.create();
                mSubjects.put(permission, subject);
            }
            //并且添加到list中
            list.add(subject);
        }

        //如果有未请求的权限
        if (!unrequestedPermissions.isEmpty()) {
            startShadowActivity(unrequestedPermissions
                    .toArray(new String[unrequestedPermissions.size()]));
        }
        return Observable.concat(Observable.from(list));
    }

    void startShadowActivity(String[] permissions) {
        log("startShadowActivity " + TextUtils.join(", ", permissions));
        Intent intent = new Intent(mCtx, ShadowActivity.class);
        intent.putExtra("permissions", permissions);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mCtx.startActivity(intent);
    }

代码如上,注释非常清晰,整体上就是将已经允许的权限和已经拒绝过的权限添加到list中,并且将还未请求的权限分别添加到mSubjects与list中。然后调用startShadowActivity();方法。最后通过Observable.concat(Observable.from(list));返回。这里主要包含PublishSubject与concat()操作符的知识:

6.PublishSubject对象

从PublishSubject的文档中,可以看出是继承自Subject,Subject是既可以充当Observer又能充当Observable的。从文档中的Example中可以看到订阅PublishSubject的observer只会接收到订阅之后PublishSubject发送的数据,但是本项目中并没有体现出此特性,主要是利用PublishSubject中的onNext()和onCompleted()方法,这里大致了解这么多,下面是Example的代码:

PublishSubject<Object> subject = PublishSubject.create();    
// observer1 will receive all onNext and onCompleted events    
subject.subscribe(observer1);    
subject.onNext("one");    
subject.onNext("two");    
// observer2 will only receive "three" and onCompleted    
subject.subscribe(observer2);    
subject.onNext("three");    
subject.onCompleted();

7.concat()操作符

Concat操作符将多个Observable结合成一个Observable并发射数据,并且严格按照先后顺序发射数据,前一个Observable的数据没有发射完,是不能发射后面Observable的数据的。引用自此篇文章。所以在本项目中Concat()是为了保证请求的权限按顺序返回。接下来我们看看ShadowActivity的实现:

8.ShadowActivity的实现

@TargetApi(Build.VERSION_CODES.M) 
 public class ShadowActivity extends Activity {        
@Override      
protected void onCreate(Bundle savedInstanceState) {          
super.onCreate(savedInstanceState);         
 if (savedInstanceState == null) {              
handleIntent(getIntent());         
 }      }       
 @Override      
protected void onNewIntent(Intent intent) {          
handleIntent(intent);      }        
private void handleIntent(Intent intent) {         
 String[] permissions = intent.getStringArrayExtra("permissions");          
requestPermissions(permissions, 42);      }        
@Override      
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {         
 RxPermissions.getInstance(this).onRequestPermissionsResult(requestCode, permissions, grantResults);         
 finish();      }  }

很简单其实就是按照系统提供给我们的方法进行权限请求,最后回调RxPermissions的onRequestPermissionsResult()方法:

9.onRequestPermissionsResult()方法的实现

void onRequestPermissionsResult(int requestCode,                                      
String permissions[], int[] grantResults) {          
for (int i = 0, size = permissions.length; i < size; i++) {              
log("onRequestPermissionsResult  " + permissions[i]);              
// 取出对应的PublishSubject对象              
PublishSubject<Permission> subject = mSubjects.get(permissions[i]);              
if (subject == null) {                  
// No subject found                  
throw new IllegalStateException
("RxPermissions.onRequestPermissionsResult 
invoked but didn't find the corresponding permission request.");             
 }              
//从mSubjects移除              
mSubjects.remove(permissions[i]);              
//获取结果             
 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;              
//调用onNext()方法发送结果              
subject.onNext(new Permission(permissions[i], granted));             
 //调用onCompleted()方法。              subject.onCompleted();          }      }

简单的来说就是拿到结果并发送结果。所以就又回到了最初的ensure(permissions);方法中的request(o, permissions)之后,代码如下:

  request(o, permissions)          
// 将Observable<Permission>转换为Observable<Boolean>          
// buffer操作符          
.buffer(permissions.length)         
 // flatMap操作符          
.flatMap(new Func1<List<Permission>, Observable<Boolean>>() {              
@Override             
 public Observable<Boolean> call(List<Permission> permissions) {                 
 // 如果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();                 
 }                 
 // 遍历所有Permission,如果有一个未成功则返回false,全部成功返回true。                  
for (Permission p : permissions) {                     
 if (!p.granted) {                         
 return Observable.just(false);                     
 }                  
}                 
 return Observable.just(true);             
 }         
 });

所以这里会不断的发送Observable<Permission>对象,请求了几个权限就会发送几次,但是这里用了一个buffer()操作符,关于buffer()操作符:

10.buffer()操作符

buffer英文是缓冲区的意思。所以Buffer操作符所要做的事情就是将数据按照规定的大小做一下缓存,然后将缓存的数据作为一个集合发射出去。详细可以看这里,所以在本项目中就是讲这些Observable<Permission>转换成Observable<List<Permission>>对象,紧接着又使用了flatMap()操作符然后返回了我们最终的结果。以上就是整个的调用流程了,如果有不清楚的建议可以多多的调试RxPermission的代码以及查阅各种资料帮助理解。

11. requestEach()、ensureEach()、ensure()的实现

以上我们分析了request()方法的实现,看似好像还剩下上面三个方法没有分析。其实仔细看的同学应该已经看明白了。上面三个方法其实都是差不多的。如果你看懂了request()方法的实现,那么这三个方法你一定能看懂,有兴趣的同学可以自行去源码里研究。

4.个人评价

其实Android 6.0的权限处理我自己在项目中都没有使用过,因为拿目前国内市场来说,首先Android 6.0的手机占有量非常少。再者我们可以使用很简单的方法将targetSdkVersion设置为22来兼容6.0的权限处理。所以目前项目中应该很少需要使用RxPermissions这个项目。但是这个项目作为RxJava的学习资料是相当的好。从中我们可以学到大量的RxJava相关的使用知识。如果你现在在学习RxJava,强烈推荐这个项目。

5.RxJava相关文章

RxJava 

深入浅出RxJava(大头鬼教父的文章) 

给 Android 开发者的 RxJava 详解 

RxJava 与 Retrofit 结合的最佳实践 

RxJava的操作符(有四篇) 

RxJava操作符 (有八篇) 

那些年我们错过的响应式编程 

不要打破链式:使用Rxjava的compose()操作符 

当EventBus遇上RxJava 

Rx小鄧子的简书相当多RxJava相关文章

 

 

   
5392 次浏览  评价: 差  订阅 捐助
 
相关文章

云计算的架构
对云计算服务模型
云计算核心技术剖析
了解云计算的漏洞
 
相关文档

云计算简介
云计算简介与云安全
下一代网络计算--云计算
软浅析云计算
 
相关课程

云计算原理与应用
云计算应用与开发
CMMI体系与实践
基于CMMI标准的软件质量保证
 

深度解析---云安全
汉周云计算白皮书简版
基于云计算的通讯录产品设计
云计算呼叫中心的应用
中国式的云计算服务模式
云计算技术和体系结构调研
相关培训课程

云计算原理与应用
Windows Azure 云计算应用

摩托罗拉 云平台的构建与应用
通用公司GE Docker原理与实践
某研发中心 Openstack实践
知名电子公司 云平台架构与应用
某电力行业 基于云平台构建云服务
云计算与Windows Azure培训
北京 云计算原理与应用
 
 
 
 
 
每天2个文档/视频
扫描微信二维码订阅
订阅技术月刊
获得每月300个技术资源
 
 

关于我们 | 联系我们 | 京ICP备10020922号 京公海网安备110108001071号