[toc]
RxPermissions 源码解析
简介
RxPermissions 是基于 RxJava 开发的用于帮助 在Android 6.0 中处理运行时权限检测的框架。在 Android 6.0 中增加了对危险权限的动态申请,而不是像 Android 6.0 之前的默认全部获取的方式。
原始动态权限的获取
如果按照以往的获取权限方式的话,那么我们获取权限一般需要有 3 个步骤,第一步是先判断当前是否已经获取到该权限了;第 2 步申请对应的权限;第 3 步在 Activity 或者 Fragment 中处理获取权限的结果。具体的实现步骤如下:
step 1:判断权限是否已经获取。
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { //用于开发者提示用户权限的用途 } else { //申请权限 }
step 2:申请权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);
step 3:结果处理
@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { // 判断请求码,确定当前申请的权限 if (requestCode == REQUEST_CAMERA) { //判断权限是否申请通过 if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { //授权成功 } else { //授权失败 } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }
RxPermissions 的简单使用
其实 RxPermissions 的使用方式有两种
方式 1:
RxPermissions rxPermissions = new RxPermissions(MainActivity.this); rxPermissions .request(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)//这里填写所需要的权限 .subscribe(new Consumer<Boolean>() { @Override public void accept(Boolean aBoolean) throws Exception { if (aBoolean) { // 通过 }else{ // 拒绝 } } });
方式 2:结合 RxBinding 来使用
RxPermissions rxPermissions = new RxPermissions(MainActivity.this);// Must be done during an initialization phase like onCreateRxView.clicks(findViewById(R.id.enableCamera)) .compose(rxPermissions.ensure(Manifest.permission.CAMERA)) .subscribe(granted -> { // R.id.enableCamera has been clicked });
源码分析
整体介绍
接着我们来对这个 RxPermissions 进行一个源码的解析,但是打开源码的时候,我们可以发现,这个库里面,其实就只有 3 个类:RxPermissions、RxPermissionsFragment、Permission
RxPermissions
最主要的实现类,利用 rxjava,为我们提供了方便权限申请的类
RxPermissionsFragment
是一个 fragment,主要的动态权限获取类
Permission
定义的权限的 model 类
源码分析
RxPermissions 实例创建
对于源码的分析,我们应该先从简单的使用入手。下面我们可以先看看实例化 RxPermissionsFragment 的时候是做了什么?
RxPermissionsFragment mRxPermissionsFragment; public RxPermissions(@NonNull Activity activity) { mRxPermissionsFragment = getRxPermissionsFragment(activity); }
我们可以看到,上面的代码中,实例化 RxPermissionsFragment 的时候,里面先创建了一个 RxPermissionsFragment 的实例。我们再接着看 getRxPermissionsFragment 这个方法的实现。
private RxPermissionsFragment getRxPermissionsFragment(Activity activity) { // 查找 RxPermissionsFragment 是否已经被添加了 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; }
在 getRxPermissionsFragment() 这个方法中,首先是先查找当前是否已经添加了这个 rxPermissionsFragment 的实例,如果已经添加,那么直接返回已经添加的实例,如果没有添加过的话,那么就重新再创建一个 RxPermissionsFragment 实例并提交;
private RxPermissionsFragment findRxPermissionsFragment(Activity activity) { return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG); }
到此,rxPermissionsFragment 的实例化已经完成,接着我们需要看看 request 这个方法中实现了什么。
request 方法
public Observable<Boolean> request(final String... permissions) { return Observable.just(TRIGGER).compose(ensure(permissions)); }
static final Object TRIGGER = new Object();
从上面的代码中,我们可以看到,request 方法中需要传入的参数是一个 权限的数组,返回值是 Observable<Boolean> 对象。Observable.just(TRIGGER) 是快捷创建一个 Observable 的方式,由于 TRIGGER 是一个空的 Object 对象,所以 TRIGGER 就是一个占位符而已,Observable.just(TRIGGER) 创建的是一个 Observable<Object>,之后通过 compose 将 Observable<Object> 转化为 Observable<Boolean> 并返回。在 compose 中需要的参数是一个 ObservableTransformer,那么我们接着看 ensure() 这个方法。
ensure(permissions);
public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) { // 创建一个Transformer对象返回 return new ObservableTransformer<T, Boolean>() { @Override public ObservableSource<Boolean> apply(Observable<T> o) { //request(o, permissions) 方法返回 Observable<Permission> 对象 return request(o, permissions) // 将 Observable<Permission> 转换为 Observable<Boolean>,在这里会等待所有的权限都返回了一次性发射数据。 .buffer(permissions.length) .flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() { @Override public 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); } }); } }; }
在 ensure 的这个方法中,最终会返回的是 ObservableTransformer<T, Boolean> 对象。接着我们看看 ObservableTransformer 的匿名实现类里面的 apply 方法,这里实现的就是将 Observable<Permission> 转换为 Observable<Boolean> 的操作。我们对 apply 这个方法里面的代码进行简化一下。
return request(o,permissions) .buffer(permissions.length) .flatMap(new Function<List<Permission>, ObservableSource<Boolean>>{});
request() 方法返回 Observable<Permission> 对象
buffer(len) 操作符将一个 Observable<Permission> 变换为 Observable<List<Permission>>,原来的 Observable 正常发射数据,变换产生的 Observable 发射这些数据的缓存集合。buffer 将数据缓存到一个集合当中,然后在适当(比如:所有请求的权限结果都返回了)的时机一起发送。
flatMap() 方法将 Observable<List<Permission>> 转化为 Observable<Boolean>
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>>() { @Override public Observable<Permission> apply(Object o) throws Exception { return requestImplementation(permissions); } }); }
在 request 这个方法里面,其实 oneOf() 和 pending() 方法我们可以忽略的,主要的话,我们应该关注 requestImplementation(final String... permissions) 这个方法,在这个方法里面,主要实现了权限的请求。
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. // 权限已经被同意或者不是 Android 6.0 以上版本,创建一个 同意的 Permission 对象。 list.add(Observable.just(new Permission(permission, true, false))); continue; } if (isRevoked(permission)) { // 权限被拒绝,返回一个 拒绝的 Permission 对象。 list.add(Observable.just(new Permission(permission, false, false))); continue; } PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission); // 如果 subject 不存在,那么创建一个 subject。 if (subject == null) { unrequestedPermissions.add(permission); subject = PublishSubject.create(); mRxPermissionsFragment.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)); }
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 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(); } }
RxJava 操作符
Observable.just()
just 操作符是将一个对象转化为 Observable 的操作符。这个对象可以是一个数字、字符串或者是数组对象等,是 RxJava 中快速创建一个 Observable 对象的操作符。如果有 subscriber 订阅的话,那么会依次调用 onNext() 和 OnComplete() 方法。所以这里只是创建了一个 Observable 对象,方便后续的调用。
compose(Transformer)操作符
compose 操作符是对 Observable 对象的整体转化。例如:通过 Transformer,我们可以将 Observable<Object> 对象转换成 Observable<Boolean> 对象了。
public static ObservableTransformer<String,Boolean> getTransformer(){ return new ObservableTransformer<String, Boolean>() { @Override public ObservableSource<Boolean> apply(Observable<String> upstream) { return upstream.flatMap(new Function<String, ObservableSource<Boolean>>() { @Override public ObservableSource<Boolean> apply(String s) throws Exception { return Observable.just(true); } }); } }; }
/** * 线程切换 * @return */ public static <T> ObservableTransformer<T,T> getScheduler(){ return new ObservableTransformer<T, T>() { @Override public ObservableSource<T> apply(Observable<T> upstream) { return upstream.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } }; }
buffer 操作符
buffer 操作符将一个 Observable 变换为另一个,原来的 Observable 正常发射数据,变换产生的 Observable 发射这些数据的缓存集合。buffer将数据缓存到一个集合当中,然后在适当的时机一起发送。
buffer(count) 以列表(List)的形式发射非重叠的缓存,每一个缓存至多包含来自原始Observable的count项数据(最后发射的列表数据可能少于count项)
例如:缓存 2 个数据之后,再发送数据(调用 buffer(count) 函数)
Observable.just(1,2,3,4,5,6) .buffer(2) .subscribe(integers -> { Log.i(TAG, "accept size: "+integers.size()); for (Integer integer : integers) { Log.i(TAG, "accept: "+integer); } });
输出结果
2018-12-14 11:16:28.452 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2 2018-12-14 11:16:28.452 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 1 2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 2 2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2 2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 3 2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 4 2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2 2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 5 2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 6
例如:缓存 3 个数据,再发送数据,每次移动 1 步
Observable.just(1,2,3,4) .buffer(3,1) .subscribe(integers -> { Log.i(TAG, "accept size: "+integers.size()); for (Integer integer : integers) { Log.i(TAG, "accept: "+integer); } });
输出结果
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 3 2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 1 2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 2 2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3 2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 3 2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 2 2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3 2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4 2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2 2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3 2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4 2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 1 2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
concat 操作符
是接收若干个Observables,发射数据是有序的,不会交叉。
Subject
作为 Observable 和 Observer 之间的桥梁
可以当做 Observable
可以当做 Observer
PublishSubject
继承至 Subject,它的 Observer 只会接收到 PublishSubject 被订阅之后发送的数据。示例代码如下;我们只会接收到 publishSubject3 和 publishSubject4;
PublishSubject<String> publishSubject = PublishSubject.create(); publishSubject.onNext("publishSubject1"); publishSubject.onNext("publishSubject2"); publishSubject.subscribe(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG, "accept: "+s); } }); publishSubject.onNext("publishSubject3"); publishSubject.onNext("publishSubject4");
执行结果
2018-12-14 11:33:18.168 29916-29916/com.luwei.lwbaselib I/LwBaseActivity: accept: publishSubject3 2018-12-14 11:33:18.168 29916-29916/com.luwei.lwbaselib I/LwBaseActivity: accept: publishSubject4
举一反三
可以看到,在 RxPermissions 这个获取权限的开源框架中,往 Activity 中添加了一个空的 Fragment,这个 fragment 才是用来发起申请权限和处理权限的请求,最后再将结果返回,这样子就避免了我们发送请求之后,还需要在 onRequestPermissionsResult 中进行处理,并判断 requestCode 等繁琐操作。想到这里,我们平时使用 startActivityForResult 时,我们也可以同样采用这样的思路来简化我们的请求。
同样的,我们采用添加空白的 fragment,来做 startActivityForResult 请求,主要的实现类有 SimpleForResult 和 SimpleOnResultFragment,ActivityResultInfo 是请求 model,接下我们先看代码。
SimpleForResult
/** * @Author: chenjianrun * @Time: 2018/12/7 * @Description: 避免调用 startActivity 时,需要 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); } }
SimpleOnResultFragment
/** * @Author: chenjianrun * @Time: 2018/12/7 * @Description: 真正调用 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() { } @Override public 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); } @Override public 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; } } } }
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; } }
简单使用示例
简单的 Activity 调用
// 简化调用 startActivityForResult 及避免在 onActivityResult 中处理繁琐的结果 SimpleForResult simpleForResult = new SimpleForResult(this); simpleForResult.startForResult(ToastActivity.class) .subscribe((resultInfo) -> { if (resultInfo.getData() != null) { ToastUtils.showLong(resultInfo.getData().getStringExtra("result")); } });
调用摄像头
/** * 打开摄像头 */ private void openCamera() { try { mTmpFile = FileUtils.createTmpFile(this); } catch (IOException e) { e.printStackTrace(); } simpleForResult.startForResult(getOpenCameraIntent(this, mTmpFile)) .subscribe((resultInfo -> { if (resultInfo.getResultCode() == RESULT_OK) { mHeadUrl = mTmpFile.getAbsolutePath(); ImageLoaderUtils.loadCircleImage(this, ivHeader, mHeadUrl); // 裁剪(如果没有要求可裁剪,也可以不要) startPictureZoom(mTmpFile); } })); } /** * 获取打开照相机的 intent,适配 Android 7.0 * @param activity * @param mTmpFile * @return */ public static Intent getOpenCameraIntent(Activity activity,File mTmpFile){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (intent.resolveActivity(activity.getPackageManager()) != null) { if (mTmpFile != null && mTmpFile.exists()) { if (Build.VERSION.SDK_INT >= 24) { // 适配 Android 7.0 intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(activity, activity.getPackageName()+".provider",mTmpFile)); } else { intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile)); } } else { Toast.makeText(activity, me.nereo.image_selector.R.string.error_image_not_exist, Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(activity, me.nereo.image_selector.R.string.msg_no_camera, Toast.LENGTH_SHORT).show(); } return intent; }
作者:广州芦苇科技App
链接:https://www.jianshu.com/p/b34d5a54a169
共同学习,写下你的评论
评论加载中...
作者其他优质文章