RxPermissions源码分析

由于在项目中用到了RxPermissions框架,所以想看看源码,顺便记录一下自己对该框架的分析过程。

下面是一篇讲有关Android权限基础知识的文章,有心的小伙伴可以参考。
使用RxPermissions(基于RxJava2)

  1. App module的build.gradle
    dependencies {

    compile ‘com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar’
    compile ‘io.reactivex.rxjava2:rxjava:2.1.13’

    }

首先需要在Activity里的onCreate方法里写入这段代码

rxPermissions=new RxPermissions(this);

接下来,我们看看上面这段话对应的源代码

public RxPermissions(@NonNull Activity activity) {mRxPermissionsFragment = getRxPermissionsFragment(activity);
}private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {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;
}private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);
}

从这段源码中,我们可以看出首先创建了一个没有布局的隐形RxPermissionsFragment,最后其实是使用这个隐形碎片放的requestPermissions()&onRequestPermissionsResult()方法实现请求权限以及回调的过程,我看之前的fix46分支见下图
这里写图片描述
是使用一个Activity,而不是用一个Fragment,不明白作者在新的分支master用碎片有什么好处?

使用rxPermissions请求两个运行时权限,请看下面这段代码

private void checkPermission(){rxPermissions.request(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION).subscribe(granted -> {if (granted) {执行其他代码} else {Toast.makeText(TrainActivity.this,"You denied the permission",Toast.LENGTH_SHORT).show();}});}

在这里涉及到了大名鼎鼎的RxJava,其实这个框架也是采用了RxJava的设计思想,如果对RxJava一点也不了解的小伙伴,可以看看下面这个人写的RxJava入门教程,自认为堪称经典,尤其是使用两个水管代替Observable&Observer的妙喻,让我在没有间断的时间内通篇看完之后有一种酣畅淋漓、欲罢不能的赶脚。下面扔出这个教程的链接:给初学者的RxJava2.0教程

下面点击request方法进入到其内部看看如何实现的

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

首先使用Observable.just(TRIGGER)获得一个Observable对象,然后再调用compose方法,网上有人说调用该方法是为了消除重复代码,但我感觉这种说法太官方,没有将这方法放置在这源码中进行解释,但我又没有明白作者之意?
后面发现compose方法需要传入的参数是ObservableTransformer< T, R >,目的是为了完成Observable< T > 的对象转换成 Observable< R > 对象。接下来我们看看ensure方法。

 public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {return new ObservableTransformer<T, Boolean>() {@Overridepublic ObservableSource<Boolean> apply(Observable<T> o) {return request(o, permissions)// Transform Observable<Permission> to Observable<Boolean>.buffer(permissions.length).flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {@Overridepublic ObservableSource<Boolean> apply(List<Permission> permissions) throws Exception {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);}});}};}

request(o, permissions)方法返回的对象是Observable< Permission >,然后调用buffer方法将所有请求的权限事件放到缓冲区当中一并发出,之后再调用flatMap方法将List< Permission > 变换成为 ObservableSource< Boolean > ,最后将结果传递给如下的代码。

.subscribe(granted -> {if (granted) {openWiFi();} else {Toast.makeText(TrainActivity.this,"You denied the permission",Toast.LENGTH_SHORT).show();}});

下面进入到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>>() {@Overridepublic Observable<Permission> apply(Object o) throws Exception {return requestImplementation(permissions);}});}

首先如果没有传入权限字符串,则抛出异常。当传入权限字符串时,则返回Observable< Permission >,有博客说oneof方法没有实际的意义,当时我在想为什么这样写,而不是写成Observable.just(TRIGGER)这样?作者的真实意图又是什么呢?自己认为该开源框架中最核心的方法就是requestImplementation(permissions),下面将对该方法进行详细分析。

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.list.add(Observable.just(new Permission(permission, true, false)));continue;}if (isRevoked(permission)) {// Revoked by a policy, return a denied Permission object.list.add(Observable.just(new Permission(permission, false, false)));continue;}PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);// Create a new subject if not existsif (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));}

首先list集合中存放着请求的所有权限,不论是否申请,而在unrequestedPermissions集合中存放着未申请的全部权限,进入到for循环中,判断每一个permission的状态,其状态共有三种:已授权(Granted)、已拒绝(Revoked)、未申请(unrequested),首先判断是否授权,如果授权则将 new Permission对象里参数granted赋值为true,其次判断是否被拒绝,如果被拒绝则将 new Permission对象里参数granted赋值为false,最后将未申请的权限放到集合unrequestedPermissions,并且给每一个未申请的权限创建一个subject对象,该对象既继承Observable,又实现了Observer。分析该方法的过程中,突然想到一个问题:当用户一开始申请权限时都应该是未申请的权限,是不是没必要设计这isGranted(permission)和isRevoked(permission)两个方法,接下来继续看未申请的权限集合unrequestedPermissions,如果未申请权限的集合不为空,则将一个ArrayList集合转化成为一个Array数据,然后再执行requestPermissionsFromFragment方法,接下来再看看该方法。

void requestPermissionsFromFragment(String[] permissions) {mRxPermissionsFragment.log("requestPermissionsFromFragment " + TextUtils.join(", ", permissions));mRxPermissionsFragment.requestPermissions(permissions);}

继续跟踪看看requestPermissions()方法

@TargetApi(Build.VERSION_CODES.M)void requestPermissions(@NonNull String[] permissions) {requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);}

到此为止,就回到了最原始的请求方法requestPermissions()与回调请求权限结果的方法onRequestPermissionsResult()中来了,我们再来看看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 subjectPublishSubject<Permission> subject = mSubjects.get(permissions[i]);if (subject == null) {// No subject foundLog.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();}}

如果请求码不等于权限请求码,则直接返回。接下来我们看看shouldShowRequestPermissionRationale()方法,该方法是AppCompact里面的。用于权限管理。
这里写图片描述

我们再来看看最后一个onRequestPermissionsResult()方法,首先是从mSubjects对象中获取到一个subject,在这里我认为subject应该看做是一个Observable(被观察者),然后再组装一个new Permission对象,然后通过onNext方法发射出去,最后再执行onComplete()方法。

RxPermissions源码分析过程就已经全部结束,中间还有很多的困惑等待解决,日后如果弄明白了,再加以补充。

近日在郭大婶的公众号中看到了他自己又新开源了一个库PermissionX,其核心的思想与RxPermissions颇有相通之处,是用kotlin语言写的,可借鉴学习。其地址如下我新开发了一个特别好用的开源库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/67041.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

围城如社会,故事如生活

生活仍在继续,围城如社会,故事如生活,但我希望:我的社会不是围城,我的生活也不仅是故事。 【第1篇】 那时年少轻狂,喜欢反复翻阅围城,喜欢背诵那些譬喻,喜欢用譬喻来评论某事,喜欢学习钱老在围城里说话的腔调,觉得玩弄文字游戏是最过瘾的事了。后来,看的次数多起来…

任正非 鸿蒙 不为手机而生,为啥华为坚持用安卓,鸿蒙怎么办?任正非:它并不是为手机而生的...

虽说因为禁令的原因&#xff0c;导致华为和谷歌安卓中止部分合作关系&#xff0c;而华为也是推出了鸿蒙系统。可是在双方合作关系之后&#xff0c;华为方面也是表示&#xff0c;自己也将会继续使用安卓系统。这种做法&#xff0c;也是让不少用户有些懵了&#xff0c;为啥华为会…

为什么其他手机厂家不用鸿蒙,手机厂商为什么不用鸿蒙系统?鸿蒙HarmonyOS热议不断...

余承东说&#xff1a;“鸿蒙OS的出发点和Android(安卓)、iOS都不一样&#xff0c;是一款全新的基于微内核的面向全场景的分布式操作系统&#xff0c;能够同时满足全场景流畅体验、架构级可信安全、跨终端无缝协同&#xff0c;以及一次开发多终端部署的要求&#xff0c;鸿蒙应未…

android图标为什么是机器人,安卓图标为什么是个机器人?让鸿蒙来告诉你

大家都知道&#xff0c;安卓是个手机操作系统。目前全球80%的智能手机使用这个操作系统。国产手机都使用这个系统&#xff0c;全球只有苹果iPhone有抗衡安卓的iOS独立系统。但是有多少人了解&#xff0c;为什么安卓操作系统&#xff0c;图标是个小机器人呢&#xff1f; 这得从安…

华为v8升级为鸿蒙,为加速鸿蒙普及,华为要给老手机升级

对于华为来说&#xff0c;在推出鸿蒙系统之后&#xff0c;最关键的就是如何增加使用鸿蒙系统的用户。目前鸿蒙系统只适配在华为以及华为荣耀的手机上&#xff0c;其他手机并不支持。也就是说如果想要尽量提升鸿蒙的普及程度&#xff0c;就要让更多的用户去使用华为手机才行。 但…

你为什么选择计算机应用专业,致新生!我为什么选择信息工程系

原标题&#xff1a;致新生&#xff01;我为什么选择信息工程系 度过长长的盛夏 站在人生新的路口 满怀对未来的期待 还有各种炽热的梦想 你是否有了坚定的方向 或许你急于了解专业的新鲜 或许你好奇学校的无限可能 又或许你还有些彷徨和迷茫 没关系 那就来听听他们 与济南理工相…

【IT资讯】继哈工大Matlab软件被美禁用后,华为、360再遭Docker软件禁令

众所周知&#xff0c;6月中旬&#xff0c;哈工大、哈工程受美商务部「实体名单」影响&#xff0c;被禁止使用 MATLAB 商业软件&#xff0c;这一消息迅速成为了人们关注的热点。 MATLAB对于现在的工科生来说是必不可少的工具&#xff0c;其日常使用率仅次于 Office 。如果 MATL…

科学家用ChatGPT写完1篇论文仅用1小时!多所高校撤销禁令

自2022年11月发布以来&#xff0c;许多人都在使用ChatGPT来帮助他们完成工作&#xff0c;各行各业的人都在使用&#xff0c;从撰写营销材料&#xff0c;到起草电子邮件&#xff0c;再到生成报告。 ChatGPT作为一种人工智能工具&#xff0c;在科研中也显示非常大的应用潜力&…

干货!拥抱大模型,探寻新时代的科研范式

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 随着ChatGPT、SAM为代表的大规模预训练模型的横空出世&#xff0c;对于人工智能、自然语言处理、计算机视觉以及软件开发等领域都带来了巨大的影响。2023年4月12日&#xff0c;AI TIME与上海交通大学人工智能研…

Python开源项目周排行 2023年第12周

原文地址&#xff1a;https://www.python1989.com/github-python-weekly/202312/ #2023年第12周2023年4月8日1Public APIs一个通过 MaShape 市场整合的世界上最全的 API 接口目录&#xff0c;支持关键词搜索和添加 API 数据&#xff0c;方便开发者快速的找到自己想要的 API。2A…

BI界的ChatGPT,它有什么厉害之处

​ChatGPT火了&#xff0c;注册用户从0到1亿&#xff0c;仅用了2个月时间。ChatGPT的背后是大数据、大模型、大算力&#xff0c;是AI的能力集中化的典型场景。那么在BI界&#xff0c;是否也有一款像ChatGPT一样智能BI软件&#xff0c;只要告诉它我们想看啥数据&#xff0c;它噔…

Finetuner+:为企业实现大模型微调和私有化部署

如 ChatGPT、GPT4 这样的大型语言模型就像是你为公司请的一个牛人顾问&#xff0c;他在 OpenAI、Google 等大公司被预训练了不少的行业内专业知识&#xff0c;所以加入你的公司后&#xff0c;你只需要输入 Prompt 给他&#xff0c; 介绍一些业务上的背景知识&#xff0c;他就能…

Sealos 私有化部署完全指南

Sealos 用了五年的时间从一个 K8s 一键安装工具蜕变成了一个真正的云操作系统&#xff0c;将产品体验提升到了极致&#xff0c;也收获了 10w 的社区用户。 一个多月前&#xff0c;Sealos 正式发布了公有云托管版本&#xff0c;社区用户狂喜&#xff0c;纷纷寻找私有化部署教程…

带你搞懂人工智能、机器学习和深度学习!

不少高校的小伙伴找我聊入门人工智能该怎么起步&#xff0c;如何快速入门&#xff0c;多长时间能成长为中高级工程师&#xff08;聊下来感觉大多数学生党就是焦虑&#xff0c;毕业即失业&#xff0c;尤其现在就业环境这么差&#xff09;&#xff0c;但聊到最后&#xff0c;很多…

AI 工具合辑盘点(十一)持续更新 之 AI 学术研究工具

许多学生和研究人员已经在利用人工智能进行研究。它可以让你更容易地了解最新研究成果&#xff0c;并帮助你组织和正确引用你最喜爱的研究论文。 从生成长篇研究论文摘要到通知你领域内的新趋势&#xff0c;研究中的AI工具节省了大量时间和精力。如果你在学术界&#xff0c;那…

一款全新的基于GPT4的Python神器,关键还免费

chartgpt大火之后&#xff0c;随之而来的就是一大类衍生物了。 然后&#xff0c;今天要给大家介绍的是一款基于GPT4的新一代辅助编程神器——Cursor。 它最值得介绍的地方在于它免费&#xff0c;我们可以直接利用它来辅助我们编程&#xff0c;真正做到事半功倍。 注意&#…

三网快速充值话费通道源码

话费充值 基于Vue2.0开发的话费充值APP&#xff0c;数据接口主要调用 聚合数据 提供的话费充值API实现。很关键的一点因为我聚合账户没有钱&#xff0c;所以没办法来真正的提交钱来测试&#xff0c;不过丝毫不影响&#xff0c;因为这里我前端已经模拟了下单成功后返回的数据(和…

小程序源码:社群微群人脉系统小程序版本源码下载带流量主功能实现广告效益

现在因为小编在实现新版本的功能添加与更新 所以小编就把这一款开源分享给大家吧! 分享出来考虑到大家服务器等等效益所以小编就把后台给砍掉了 所以大家就直接前端上传到微信开发者工具即可使用 本款小程序群二维码自动采集推送的,所以大家不用担心没有群难运营 小编运营…

一套ThinkPHP微信小程序商城源码带后台管理

ThinkPHP微信小程序商城源码带后台管理 源码类型&#xff1a;全开源免费分享&#xff0c;需要学习可私信 注意事项&#xff1a; 1、App/Common/Conf/db.php 数据库连接参数修改&#xff1b; 2、App/Api/Conf/config.php 微信小程序的appid、secret、mchid、key、notify_url&a…

开源的微信商城,含小程序端,后台管理系统,服务器后端,附完整源码

微信小程序商城 项目概述 一个完整的微信小程序商城&#xff0c;包含微信小程序&#xff0c;管理系统&#xff0c;服务端后台&#xff0c;项目预览如下&#xff1a; 微信小程序 -微信小程序包含主页、商品分类、商品详情、加购物车&#xff0c;微信授权登录&#xff0c;微信…