前言
AndroidM(6.0)开始,系统增加了运行时动态权限,目的在于保护用户隐私,防止一些敏感的危险权限在应用安装时被随意获取,用户可以清晰地选择是否允许app某项权限,就算没有给予某个权限,也不影响其他功能的使用,不至于令用户无法安装。以下权限都被列为危险权限,即需要运行时动态获取的权限。
身体传感器
日历
摄像头
通讯录
地理位置
麦克风
电话
短信
存储空间
原始使用方法
第一步是先判断当前是否已经获取到该权限了;第 2 步申请对应的权限;第 3 步在 Activity 或者 Fragment 中处理获取权限的结果。具体的实现步骤如下:
- step 1:判断权限是否已经获取。
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {//第一步,检查用户是否具有该权限
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an explanation 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; 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.
}
} else {
// Permission has already been granted
}
- step 2:申请权限
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
- step 3:结果处理
@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.
}
}
RxPermissions
[RxPermissions**](https://github.com/tbruyelle/RxPermissions)**原始的操作的方式其实类似于startActivityForResult
这种启动Activity的方法,也是会有具体的回调方法,但是如果每次都需要这样写太过于繁琐,所以需要对其进行封装,而RxPermissions
这个库就对其进行了很好的封装该库允许将RxJava
与新的Android M权限模型一起使用。基本用法:
final RxPermissions rxPermissions = new RxPermissions(this); // where this is an Activity or Fragment instance
rxPermissions
.request(Manifest.permission.CAMERA)
.subscribe(granted -> {
if (granted) { // Always true pre-M
// I can control the camera now
} else {
// Oups permission denied
}
});
还有其他方法参考看https://github.com/tbruyelle/RxPermissions
整体介绍
整个库里面,其实就只有 4 个类:RxPermissions、RxPermissionsFragment、Permission
- RxPermissions 最主要的实现类,利用 rxjava,为我们提供了方便权限申请的类
- RxPermissionsFragment 是一个 fragment,主要的动态权限获取类
- Permission 定义的权限的 model 类
- BuildConfig 没什么用的配置类
源码分析
RxPermissions 实例创建
RxPermissions.Lazy<RxPermissionsFragment> mRxPermissionsFragment;
public RxPermissions(@NonNull FragmentActivity activity) {
this.mRxPermissionsFragment = this.getLazySingleton(activity.getSupportFragmentManager());
}
public RxPermissions(@NonNull Fragment fragment) {
this.mRxPermissionsFragment = this.getLazySingleton(fragment.getChildFragmentManager());
}
@NonNull
private RxPermissions.Lazy<RxPermissionsFragment> getLazySingleton(@NonNull final FragmentManager fragmentManager) {
return new RxPermissions.Lazy<RxPermissionsFragment>() {
private RxPermissionsFragment rxPermissionsFragment;
public synchronized RxPermissionsFragment get() {
if (this.rxPermissionsFragment == null) {
this.rxPermissionsFragment = RxPermissions.this.getRxPermissionsFragment(fragmentManager);//1 获取RxPermissionsFragment的方法
}
return this.rxPermissionsFragment;
}
};
}
我们可以看到,上面的代码中,实例化 RxPermissions 的时候,里面先创建了一个 RxPermissionsFragment 的实例。关键代码1处调用getRxPermissionsFragment
这个方法。
private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
// 查找 RxPermissionsFragment 是否已经被添加了
RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
boolean isNewInstance = rxPermissionsFragment == null;
// 如果还没有存在,则创建Fragment,并添加到Activity中
if (isNewInstance) {
rxPermissionsFragment = new RxPermissionsFragment();
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager
.beginTransaction()
.add(rxPermissionsFragment, TAG)
.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
return rxPermissionsFragment;
}
在 getRxPermissionsFragment() 这个方法中,首先是先查找当前是否已经添加了这个 rxPermissionsFragment 的实例,如果已经添加,那么直接返回已经添加的实例,如果没有添加过的话,那么就重新再创建一个 RxPermissionsFragment 实例并提交;
// 利用tag去找是否已经有该Fragment的实例
private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {
return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);
}
通过以上的代码可以知道,在创建RxPermissions的对象中,其实就是获取Fragment的实例而已,既然这样,我们就需要到这个Fragment的实现中,看它在被创建的时候做了什么事情
// Fragment的构造方法
public RxPermissionsFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 禁止横竖屏切换时的Fragment的重建
setRetainInstance(true);
}
到此,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
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
return request(o,permissions)
.buffer(permissions.length)
.flatMap(new Function<List<Permission>, ObservableSource<Boolean>>{});
- request() 方法返回 Observable
对象 - buffer(len) 操作符将一个 Observable
变换为 Observable - ,原来的 Observable 正常发射数据,变换产生的 Observable 发射这些数据的缓存集合。buffer 将数据缓存到一个集合当中,然后在适当(比如:所有请求的权限结果都返回了)的时机一起发送。
- flatMap() 方法将 Observable
- 转化为 Observable
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 对象转换成 Observable 对象了。
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
总结
可以看到,在Fragment被创建时,并没有重写onCreateView
()方法,来进行布局文件的加载,只是重写了onCreate()方法,然后禁止了横竖屏Fragment的重建,这就代表说,这个Fragment是一个没有布局的隐形Fragment,不会在屏幕上展示出来,但是这个Fragment却是关键,权限的申请与申请结果的回调都是在Fragment中完成的,这样,我们才不需要为申请结果重写回调方法