海丰网站建设,网站制作需要学习什么,上海网站开发一对一培训,新密做网站公司[toc] RxPermissions 源码解析 简介 RxPermissions 是基于 RxJava 开发的用于帮助 在Android 6.0 中处理运行时权限检测的框架。在 Android 6.0 中增加了对危险权限的动态申请#xff0c;而不是像 Android 6.0 之前的默认全部获取的方式。 原始动态权限的获取 如果按照以往的获… [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:结果处理Override
public 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 的使用方式有两种 方式 1RxPermissions rxPermissions new RxPermissions(MainActivity.this);rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE)//这里填写所需要的权限.subscribe(new ConsumerBoolean() {Overridepublic 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 onCreate
RxView.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 ObservableBoolean request(final String... permissions) {return Observable.just(TRIGGER).compose(ensure(permissions));}
复制代码 static final Object TRIGGER new Object();
复制代码从上面的代码中我们可以看到request 方法中需要传入的参数是一个 权限的数组返回值是 Observable 对象。Observable.just(TRIGGER) 是快捷创建一个 Observable 的方式由于 TRIGGER 是一个空的 Object 对象所以 TRIGGER 就是一个占位符而已Observable.just(TRIGGER) 创建的是一个 Observable,之后通过 compose 将 Observable 转化为 Observable 并返回。在 compose 中需要的参数是一个 ObservableTransformer那么我们接着看 ensure() 这个方法。 ensure(permissions); public T ObservableTransformerT, Boolean ensure(final String... permissions) {// 创建一个Transformer对象返回return new ObservableTransformerT, Boolean() {Overridepublic ObservableSourceBoolean apply(ObservableT o) {//request(o, permissions) 方法返回 ObservablePermission 对象return request(o, permissions)// 将 ObservablePermission 转换为 ObservableBoolean在这里会等待所有的权限都返回了一次性发射数据。.buffer(permissions.length).flatMap(new FunctionListPermission, ObservableSourceBoolean() {Overridepublic ObservableSourceBoolean apply(ListPermission permissions) throws Exception {// 如果permissions为空那么直接返回Observable.empty();if (permissions.isEmpty()) {// Occurs during orientation change, when the subject receives onComplete.// In that case we dont 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 的这个方法中最终会返回的是 ObservableTransformerT, Boolean 对象。接着我们看看 ObservableTransformer 的匿名实现类里面的 apply 方法这里实现的就是将 Observable 转换为 Observable 的操作。我们对 apply 这个方法里面的代码进行简化一下。 return request(o,permissions).buffer(permissions.length).flatMap(new FunctionListPermission, ObservableSourceBoolean{});
复制代码request() 方法返回 Observable 对象buffer(len) 操作符将一个 Observable 变换为 ObservableList原来的 Observable 正常发射数据变换产生的 Observable 发射这些数据的缓存集合。buffer 将数据缓存到一个集合当中然后在适当(比如所有请求的权限结果都返回了的时机一起发送。flatMap() 方法将 ObservableList 转化为 Observablerequest(o, permissions); private ObservablePermission 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 FunctionObject, ObservablePermission() {Overridepublic ObservablePermission apply(Object o) throws Exception {return requestImplementation(permissions);}});}复制代码在 request 这个方法里面其实 oneOf() 和 pending() 方法我们可以忽略的主要的话我们应该关注 requestImplementation(final String... permissions) 这个方法在这个方法里面主要实现了权限的请求。 requestImplementation TargetApi(Build.VERSION_CODES.M)private ObservablePermission requestImplementation(final String... permissions) {ListObservablePermission list new ArrayList(permissions.length);ListString 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;}PublishSubjectPermission 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 subjectPublishSubjectPermission subject mSubjects.get(permissions[i]);if (subject null) {// No subject foundLog.e(RxPermissions.TAG, RxPermissions.onRequestPermissionsResult invoked but didnt 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 对象转换成 Observable 对象了。 public static ObservableTransformerString,Boolean getTransformer(){return new ObservableTransformerString, Boolean() {Overridepublic ObservableSourceBoolean apply(ObservableString upstream) {return upstream.flatMap(new FunctionString, ObservableSourceBoolean() {Overridepublic ObservableSourceBoolean apply(String s) throws Exception {return Observable.just(true);}});}};}
复制代码/*** 线程切换* return*/public static T ObservableTransformerT,T getScheduler(){return new ObservableTransformerT, T() {Overridepublic ObservableSourceT apply(ObservableT 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可以当做 ObserverPublishSubject 继承至 Subject它的 Observer 只会接收到 PublishSubject 被订阅之后发送的数据。示例代码如下我们只会接收到 publishSubject3 和 publishSubject4 PublishSubjectString publishSubject PublishSubject.create();publishSubject.onNext(publishSubject1);publishSubject.onNext(publishSubject2);publishSubject.subscribe(new ConsumerString() {Overridepublic 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 和 SimpleOnResultFragmentActivityResultInfo 是请求 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 ObservableActivityResultInfo startForResult(Intent intent) {return mSimpleOnResultFragment.startForResult(intent);}public ObservableActivityResultInfo 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 MapInteger, PublishSubjectActivityResultInfo mSubjects new HashMap();private static MapInteger, SimpleForResult.Callback mCallbacks new HashMap();public SimpleOnResultFragment() {}Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setRetainInstance(true);}public ObservableActivityResultInfo startForResult(final Intent intent) {int requestCode generateRequestCode();PublishSubjectActivityResultInfo 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);}Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);//rxjava方式的处理PublishSubjectActivityResultInfo 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.0intent.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;}复制代码