看完这篇再不会Android权限组件设计,我跪搓衣板!

先看下 Demo 的 代码

不上 gif 了,录这个时间太长,gif 太大网页很卡。Demo 的思路如下,正常的判断权限,有3个回调,用户确认给予权限,用户不给,和用户点选不在显示系统权限弹窗。这里我们在用户不显示弹窗后的回调里启动系统权限设置页,在用户关闭权限设置页面过后,我们再检测下=刚刚用户给没给权限,没给权限的话就自己显示个弹窗,提示用户不给权限就关闭页面

Demo 代码如下:

class?PermissionActivity : AppCompatActivity() {

????override fun onCreate(savedInstanceState: Bundle?) {
????????super.onCreate(savedInstanceState)
????????setContentView(R.layout.activity_permission)

????????btn_permission.setOnClickListener{

????????????PermissionManage
????????????????????.with(this)
????????????????????.permission(Manifest.permission.CALL_PHONE)
????????????????????.permission(Manifest.permission.CAMERA)
????????????????????.permission(Manifest.permission.READ_PHONE_STATE)
????????????????????.onSuccess { Toast.makeText([email protected],?"申请成功", Toast.LENGTH_SHORT).show() }
????????????????????.onDenial { Toast.makeText([email protected],?"用户拒绝", Toast.LENGTH_SHORT).show() }
????????????????????.onDontShow { IntentUtils.startSettingActivityForResult(this,?200) }
????????????????????.run()
????????}
????}

????override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

????????if?(requestCode ==?200) {

????????????var?permissions = listOf(Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE)
????????????if?(PermissionManage.isHavePermissions(this, permissions)) {
????????????????Toast.makeText(this,?"欢迎您给予的权限", Toast.LENGTH_SHORT).show()
????????????}?else?{
????????????????showDialog()
????????????}
????????}
????}

????private?fun showDialog() {

????????var?build: AlertDialog.Builder = AlertDialog.Builder(this)
????????build.setMessage("缺乏权限,请求您给予权限")
????????build.setPositiveButton("申请权限", object : DialogInterface.OnClickListener {
????????????override fun onClick(dialog: DialogInterface?, which: Int) {
????????????????IntentUtils.startSettingActivityForResult([email protected],?200)
????????????????dialog?.dismiss()
// dialog?.cancel()
????????????}
????????})
????????build.setNegativeButton("不给权限", object : DialogInterface.OnClickListener {
????????????override fun onClick(dialog: DialogInterface?, which: Int) {
????????????????Toast.makeText([email protected],?"对不起,某些权限是必备选择,不给权限不能运行", Toast.LENGTH_SHORT).show()
????????????????dialog?.dismiss()
[email protected]()
????????????}
????????})
????????build.show()
????}

}

组件封装思路

1. 要好看,响应式函数式编程思想,提供链式调用

这点很重要,组件封装完了是要给小伙伴们和自己用的,用起来费时费力,不好理解,不清不楚的都不行,达不到简单易懂易用的组件都是不合格的,从这点来说,其实 Fresco 的 API 就不是很好,当然 Fresco 是非常复杂的了,但是另一个图片加载的小伙伴 Glide API 就很 Nice 啦

这部分就是我封装的权限组件的 API 了,仿照函数式编程,提供链式调用,这样的代码很好看,非常容易理解逻辑。函数式编程在处理连续复杂逻辑的代码上有天然的优势,其风格以清晰著称,是我们封装工具类组件的不二选择

PermissionManage
????????????????????.with(this)
????????????????????.permission(Manifest.permission.CALL_PHONE)
????????????????????.permission(Manifest.permission.CAMERA)
????????????????????.permission(Manifest.permission.READ_PHONE_STATE)
????????????????????.onSuccess?{?Toast.makeText([email protected],?"申请成功", Toast.LENGTH_SHORT).show() }
????????????????????.onDenial?{?Toast.makeText([email protected],?"用户拒绝", Toast.LENGTH_SHORT).show() }
????????????????????.onDontShow?{?IntentUtils.startSettingActivityForResult(this,?200) }
????????????????????.run()

2. 第三方库高度,无痕可替换

我使用的是 AndPermission 这个开源库,来看下我对 AndPermission 的包装

2.1 - 抽取接口第三方权限库是干嘛的,就是提供权限申请验证的,抽泣其公共功能,就是1个,给参数然后执行,就是这么简单,为什么,因为功能单一呗,即使请求验证权限

interface?IPermissionExecuter?{

????fun run(permissionConfig: PermissionConfig)
}

2.2 - 实现接口 ,包装第三方库

class?AndPermissinExecuterImpl?:?IPermissionExecuter?{

????override?fun?run(permissionConfig: PermissionConfig)?{
????????AndPermission.with(permissionConfig.context)
????????????????.permission(permissionConfig.permissions.toTypedArray())
????????????????// 用户给权限了
????????????????.onGranted({ permissions: List<String> -> permissionConfig.onSuccessAction() })
????????????????// 用户拒绝权限,包括不再显示权限弹窗也在此列
????????????????.onDenied({ permissions: List<String> ->
????????????????????// 判断用户是不是不再显示权限弹窗了,若不再显示的话进入权限设置页
????????????????????if?(AndPermission.hasAlwaysDeniedPermission(permissionConfig.context, permissions)) {
????????????????????????// 打开权限设置页
????????????????????????permissionConfig.onDontShowAction()
[email protected]
????????????????????}
????????????????????permissionConfig.onDenialAction()
????????????????})
????????????????.start()
????}
}

第三方权限库需要的参数基本都一样,不管有什么,我们都包装到 PermissionConfig 里面,然后通过PermissionConfig 把参数传进来执行,这样我们想要替换 第三方实现时,只要再写一个 IPermissionExecuter 的实现类就行了

2.3 - 提供一个工厂类,实现切换管理

这个就不用说了吧,工厂模式,打击都熟悉的套路了

object?ExecuterFactor?{

[email protected]
????val AND_PERMISSION =?"AND_PERMISSION"

[email protected]
????val RX_PERMISSION =?"RX_PERMISSION"

[email protected]
????val DEFAULT_EXECUTER = AND_PERMISSION

[email protected]
????fun getInstance(): IPermissionExecuter {
????????return?getInstance(DEFAULT_EXECUTER)
????}

[email protected]
????private?fun?getInstance(type: String):?IPermissionExecuter?{

????????return?when?(type) {
????????????AND_PERMISSION?->?AndPermissinExecuterImpl()
????????????DEFAULT_EXECUTER?->?AndPermissinExecuterImpl()
????????????else?->?AndPermissinExecuterImpl()
????????}
????}
}

3. 抽取公共参数,使用 build 构建

上面我们把第三方所需参数包装成了一个类 PermissionConfig,我们来看看这个类

class?PermissionConfig {

????lateinit?var?context: Context
????// 权限申请成功时回调
????var?onSuccessAction: () -> Unit = {}
????// 权限申请失败时回调
????var?onDenialAction: () -> Unit = {}
????// 用户设置不显示权限申请弹窗时回调
????var?onDontShowAction: () -> Unit = {}
????// 权限集合
????var?permissions = mutableListOf<String>()

????private?var?type:?String?= ExecuterFactor.DEFAULT_EXECUTER

????/**
?????* 添加权限
?????*/
????fun addPermission(permission:?String) {
????????if?(!permission.isEmpty()) permissions.add(permission)
????}

????/**
?????* 设置类型
?????*/
????fun setType(type:?String): PermissionConfig {
????????if?(!type.isEmpty())?this.type =?type
????????return?this
????}

????/**
?????* 执行操作
?????*/
????fun run() {
????????ExecuterFactor.getInstance().run(this)
????}
}

抽取出来的参数没几个,很好理解,所需要的参数,用集合来接收因为可能有多个嘛,然后是3个回调,同意,不同意,关闭权限弹窗,借助 kotlin 的语言,我们不要再像 java 一样去写一个接口了,直接声明成空实现就行,也没有 null 的问题,然后提供设置这几个参数的方法即可

但是吧,我们不能就这么直接使用 PermissionConfig ,因为以后随着时间推移有变化,我们需要一个统一的地方来统一构建参数包装对象,这就是大家熟悉的 build 模式啦

class?PermissionBuild(var?context: Context) {

????var?permissionConfig: PermissionConfig = PermissionConfig()

????init {
????????permissionConfig.context =?this.context
????}

????/**
?????* 设置类型
?????*/
????fun?type(type:?String): PermissionBuild {
????????if?(!type.isEmpty()) permissionConfig.setType(type)
????????return?this
????}

????/**
?????* 添加权限
?????*/
????fun permission(permission:?String): PermissionBuild {
????????if?(!permission.isEmpty()) permissionConfig?.addPermission(permission)
????????return?this
????}

????/**
?????* 添加成功操作
?????*/
????fun onSuccess(onSuccessAction: () -> Unit): PermissionBuild {
????????if?(onSuccessAction !=?null) permissionConfig.onSuccessAction = onSuccessAction
????????return?this
????}

????/**
?????* 添加失败操作
?????*/
????fun onDenial(onDenialAction: () -> Unit): PermissionBuild {
????????if?(onDenialAction !=?null) permissionConfig.onDenialAction = onDenialAction
????????return?this
????}

????/**
?????* 添加不显示权限弹窗操作
?????*/
????fun onDontShow(onDontShowAction: () -> Unit): PermissionBuild {
????????if?(onDontShowAction !=?null) permissionConfig.onDontShowAction = onDontShowAction
????????return?this
????}

????/**
?????* 执行操作
?????*/
????fun run() {
????????permissionConfig.run()
????}
}

这里的 build 逻辑很简单,不写也可以,本着练手的原则还是写了,还是得益于 kotlin 的语法,方法可以直接接收函数参数,也不用我们再去写接口了,的确是方便了很多,尤其是在我们写的时候可以一气呵成,不用来回切换类,不会打断思路是非常好的

4. 提供统一入口

作为工具类,要有一个统一的入口,静态的也行,new 对象也行,这里推荐使用静态方法的方式,方便理解

class?PermissionManage {

????/**
?????* 提供相关静态入口,效仿 Glide 通过 with 绑定上下文
?????*
?????*/
????companion object {

[email protected]
????????fun?with(context: Context): PermissionBuild {
????????????return?PermissionBuild(context)
????????}

[email protected]
????????fun isHavePermission(context: Context, permission:?String):?Boolean?{
????????????return?PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context, permission)
????????}

[email protected]
????????fun isHavePermissions(context: Context, permissions: List<String>):?Boolean?{

????????????for?(it?in?permissions) {
????????????????if?(!(PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context, it)))?return?false
????????????}
????????????return?true
????????}
????}
}

类似于 Glide.with 在添加上下文之后返回 PermissionBuild 构建器用于添加数据,另外还提供了其他工具方法,用来查询是否有权限

我是从后向前走的顺序,思路是基于一步步的实现的,中间的类都是基于我要包装第三方库的目的一步步产生的,简单的功能库基本都是基于这个角度来做

看下类结构

这个组件很简单的,其实我之前用 java 写过这个权限组件,同样的思路,地址在这里:简单对权限开源库进行功能性封装?,一开始我就是想把 java 换成 kotlin ,但是改改写写,最后基本彻底抛弃以前的重新整理思路写了一遍,旧的那个组件现在看来废话太多,我差不多删了一半的类,另外我又重新考虑了一遍命名,也是基本改了一半的,这个命名在我来看是最难的

新版类结构:

老版类结构:

这么一看是不是很简单啊,虽然简单但是很好的完成了我们的目标,包装第三方组件,提供统一 API 实现,动态无缝切换第三放实现

数数我们用了几个套路:

  • 提取相同,抽象不同 - 模板模式 包装第三方实现,抽取 run 执行这个动作,把所以参数包装成统一的配置类
  • 统一切换不同第三方实现 - 工厂模式
  • build 统一构建数据 - 构造者模式
  • 提供统一接口 - 门板模式

上面基本都是套路,权限这个组件功能单一,大家可能体会不到上面这几个套路的神奇,这东西只能靠意淫来理解深化,得自己手把手的写才能有切身体会,才能最终荣辉贯通, UML 类图有时间再放上吧

最后吐槽下

在写这个组件时,测试时尼玛我居然忘了在配置文件里声明所需权限了,我怎么调试怎么都不对,我查了好多遍代码也没找到问题,老打击人了,老郁闷了,让我一天的心情都老差劲了,浪费了2个多小时时间,后来想起来了,尼玛我是抽了自己5分钟的嘴巴子,太丢了。

奉劝大家遇到问题时一定要冷静啊,不冷静的后果就是浪费人生,明明很简单的事,代码也写的很好,一次过,就是忘了配置文件这件事,其他都没问题,但是就偏偏好事变坏事,哎,冷静,遇事千万要平常心,要不自己真遭罪。

还有就是碎片化这个问题了,小米,魅族,华为手机用公版代码是打不开权限设置页面的,非的要适配,真他妈蛋疼,我又取百度了下,还好直接就找找了,写了工具类,但是考虑了下,这个工具是打开系统页面的,我就没放在权限组件里,从工能上讲风马牛不相及的事不能放一起的,这个类叫:IntentUtils ,具体我就不方了 Demo 里面可以找到这个类。

源码地址:
https://github.com/zb25810045/BW_Libs

最后

其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

上述【高清技术脑图】以及【配套的架构技术PDF】可以 加我wx:X1524478394 免费获取!

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

原文地址:https://blog.51cto.com/14332859/2465650

时间: 2024-08-29 07:09:09

看完这篇再不会Android权限组件设计,我跪搓衣板!的相关文章

看完这篇还不会自定义 View ,我跪搓衣板

自定义 View 在实际使用的过程中,我们经常会接到这样一些需求,比如环形计步器,柱状图表,圆形头像等等,这时我们通常的思路是去Google 一下,看看 github 上是否有我们需要的这些控件,但是如果网上收不到这样的控件呢?这时我们经常需要自定义 View 来满足需求. 接下来让我们开启自定义控件之路 关于自定义控件,一般辉遵循一下几个套路 首先重写 onMeasure() 方法 其次重写 onDraw() 方法 总所周知 onMeasure() 方法是用来重新测量,并设定控件的大小,我们知

Android总结篇系列:Android 权限

权限是一种安全机制.Android权限主要用于限制应用程序内部某些具有限制性特性的功能使用以及应用程序之间的组件访问.在Android开发中,基本上都会遇到联网的需求,我们知道都需要加上联网所需要的权限: 1 <uses-permission android:name="android.permission.INTERNET" /> 实际上,在开发过程中,当我们使用了某些系统特性的功能,且此类特性需要包含相应权限时,如果在AndroidManifest.xml文件中相应申明

wwwlyjustcom看完这篇,你就会Linux基本操作了,请耐看完199O8836661

只有光头才能变强这个学期开了Linux的课程了,授课的老师也是比较负责任的一位.总的来说也算是比较系统地学习了一下Linux了~本文章主要是总结Linux的基础操作以及一些简单的概念,对于开发者来说,能使用Linux做一些基本的操作是必要的!那么接下来就开始吧,当然了我的Linux仅仅是入门水平,如果有错的地方还需请大家多多包涵,并不吝在评论区指出错误~一.为什么我们要学习Linux相信大部分人的PC端都是用Windows系统的,那我们为什么要学习Linux这个操作系统呢???Windows图形

PDF怎么拆分成多个PDF,看完这篇文章你就明白了

PDF文件对于每一个经常在职场上工作的人来说,是特别常见的一个文档格式,PDF格式深受人们的喜爱,因为是特别好用的,但同时也是比较难进行编辑和修改的,特别是遇到PDF文档过长,为了方便浏览和及时查找对我们有用的内容,这就需要将PDF文档拆分成多个PDF,那么PDF怎么拆分成多个PDF?通过今天的文章就来告诉大家PDF文档拆分的方法,看完这篇文章你就明白了,那么我们就一起来看看吧.?方法一:软件拆分法借助软件:如果想要将PDF文档拆分成多个PDF,那就需要借助迅捷PDF转换器来实现,这个软件有着丰

零基础如何开始学习 Python?看完这篇从小白变大牛!

1.选择Python版本 对于Python工程师来说,Python的版本则是你们的工作环境.所以在学习之前一定要考虑选择一个合适自己的版本,Python3对零基础的小白很友好,易上手.选好版本后就可以开始学习了.创一个小群,供大家学习交流聊天如果有对学python方面有什么疑惑问题的,或者有什么想说的想聊的大家可以一起交流学习一起进步呀.也希望大家对学python能够持之以恒python爱好群,如果你想要学好python最好加入一个组织,这样大家学习的话就比较方便,还能够共同交流和分享资料,给你

关于 Docker 镜像的操作,看完这篇就够啦 !(下)

原文:关于 Docker 镜像的操作,看完这篇就够啦 !(下) 紧接着上篇<关于 Docker 镜像的操作,看完这篇就够啦 !(上)>,奉上下篇 !!! 镜像作为 Docker 三大核心概念中最重要的一个关键词,它有很多操作,是您想学习容器技术不得不掌握的.本文将带您一步一步,图文并重,上手操作来学习它. 目录: 一.Docker 删除镜像 1.1 通过标签删除镜像 1.2 通过 ID 删除镜像 1.3 删除镜像的限制 1.4 清理镜像 二.Docker 创建镜像 2.1 基于已有的镜像创建

如何更准确过滤信息?看完本篇你就知道

无论是使用Excel办公,还是浏览器搜寻关键字,都是需要通过条件过滤来实现.今天,手把手教你实现Java web项目--实现多条件过滤功能. 分页查询需求分析:在列表页面中,显示指定条数的数据,通过翻页按钮完成首页/上一页/下一页/尾页的查询数据分析:通过观察,页面上需要显示下面的几个数据:当前页:currentPage页面大小:pageSize总页数:totalPage首页:1上一页:prevPage下一页:nextPage尾页:endPage总条数:totalCount结果集:result

ae模板怎么套用?看完这篇ae模板套用教程你就懂了

首先我们要知道,模板,是什么?模板就是别人做好了的工程文件,所以东西都已经完成,不需要任何效果方面的修改了.那么ae模板怎么套用?就是你用的时候,替换.修改或者删去某些东西,变成自己的视频.比如片头LOGO模板,你肯定得要有自己的LOGO,去替换模板里的LOGO,然后渲染成片,才会成你的片头:看完这篇ae模板套用教程你就懂了. https://www.macdown.com 本站提供了海量AE模板,我们选择片头LOGO模板,做你自己的片头. 首先下载完后,打开这个模板. 然后看一眼项目栏 我用的

看完这篇你还敢说,不懂Spring中的IoC容器?

一. 什么是IoC 什么是耦合和内聚 耦合指的就是模块之间的依赖关系.模块间的依赖越多,则表示耦合度越高,相应的维护成本就越高.内聚指的是模块内功能之间的联系.模块内功能的联系越紧密,则表示内聚度越高,模块的职责也就越单一.所以在程序开发中应该尽量的降低耦合,提高内聚.也就是设计原则中的开闭原则和单一职责原则. 工厂模式 工厂模式就是用来解决程序间耦合的一种设计模式.可以把所有要创建的对象放在工厂的一个集合里,当需要使用这个对象的时候,直接从工厂里面取出来用就行. 工厂模式的优点: 一个调用者想