[Android]实现一个权限申请类

news2024/11/20 2:23:16

[Android]实现一个权限申请类

在这里插入图片描述

导言

在引入了动态权限申请之后,Android的权限申请就变得尤为繁琐,若是按照原有的方法一板一眼地进行申请,样板代码未免太多。因此本篇文章就使用ActivityResult API,来实现一个简单的权限申请类来帮助我们简化权限申请的过程。

在此之前,你可能需要了解一些关于ActivityResult API相关的知识:使用Activity Result API 清爽地请求权限 和 启动Activity。

前置知识

在介绍正式的实现过程之前还是先简单介绍一下ActivityResult API,这是AndroidX中的内容,旨在解耦Activity的职责,避免Activity中出现的大量的集中的回调代码的出现。

该API有两个重要的概念:Launcher(启动器),Contract(契约)。其中,启动器是真正帮我们去执行操作(比如申请权限)的类,而契约类则规定了启动器的行为,比如说申请权限还是启动另一个Activity。但是在我们今天的这个主题下,只需要关注申请权限这一个行为就OK了,所以也无需太过关注契约类。

除此之外,还需要注意的一点是ActivityResult 的启动器 必须要在宿主的生命周期到达 CREATED 之前就创建完毕,所以我们在设计申请类的时候必须把这一点考虑进去。

具体实现

权限检查

首先我们从简单地做起,一个权限相关的工具类必备的就是权限的检查,这个我们用原有的方法就可以了,代码如下:

    //检查权限
    fun checkPermission(context:Context,target:Array<String>):Boolean {
        for (permission in target) {
            val result = ContextCompat.checkSelfPermission(context,permission)
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false
            }
        }
        return true
    }

核心设计

关于权限申请的权限的设计,由于有Launcher的存在,所以我们有存储Launcher的诉求,自然而然我们会想到用一张HashMap去存储。之后我们需要考虑的就是如何将权限,宿主。启动器这三者映射起来,所以可以用一张二维的HashMap去存储。具体结构是这样:一个宿主对应一张HashMap,该HashMap中一个权限对应一个Launcher,如下图所示:
在这里插入图片描述
我们用这么一个HashMap去存储对应的关系:

private val ownerMap = mutableMapOf<ComponentActivity,MutableMap<String,ActivityResultLauncher<String>>>()

注册启动器 & 注销注册器

有了上边所说的Map来存储映射关系之后,我们就需要填充这张Map了,具体来说就是注册启动器的过程,这个过程也十分简单,主要就是依次找对应项,如果对应项不存在的话就新创建一项进行填充:

    //注册启动器
    fun registerLauncher(owner: ComponentActivity, permission:String, callback:ActivityResultCallback<Boolean> = Empty_Callback) {
        val launcher = owner.registerForActivityResult(ActivityResultContracts.RequestPermission(),callback)
        if (!ownerMap.containsKey(owner)) {
            ownerMap[owner] = mutableMapOf()
        }
        ownerMap[owner]!!.put(permission,launcher)

        //注册一个事件自动移除启动器
        owner.lifecycle.addObserver(object :LifecycleEventObserver{
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    unRegisterLauncher(owner,permission)
                    Log.d(TAG, "onStateChanged: Removed")
                }

            }
        })
    }

这里比较特殊的一点是为了防止内存泄漏的问题,若宿主的生命周期已经达到onDestroy则会自动将二次映射的数据项进行移除。注销注册器的代码如下所示:

    //注销启动器
    fun unRegisterLauncher(context: Context,permission: String) {
        if (ownerMap.containsKey(context) && ownerMap[context]!!.containsKey(permission)) {
            ownerMap[context]!!.remove(permission)
        }
    }

完整代码

最后,给出完整的代码,如下所示:

object PermissionUtil {
    //若不需要回调,使用此空实现
    public val Empty_Callback = object :ActivityResultCallback<Boolean> {
        override fun onActivityResult(result: Boolean) {

        }
    }

    private const val TAG = "PermissionUtil"

    private val ownerMap = mutableMapOf<ComponentActivity,MutableMap<String,ActivityResultLauncher<String>>>()

    //注册启动器
    fun registerLauncher(owner: ComponentActivity, permission:String, callback:ActivityResultCallback<Boolean> = Empty_Callback) {
        val launcher = owner.registerForActivityResult(ActivityResultContracts.RequestPermission(),callback)
        if (!ownerMap.containsKey(owner)) {
            ownerMap[owner] = mutableMapOf()
        }
        ownerMap[owner]!!.put(permission,launcher)

        //注册一个事件自动移除启动器
        owner.lifecycle.addObserver(object :LifecycleEventObserver{
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    unRegisterLauncher(owner,permission)
                    Log.d(TAG, "onStateChanged: Removed")
                }

            }
        })
    }

    //申请权限
    fun requestPermission(context: Context,permission: String):Boolean {
        val launcher = ownerMap[context]?.get(permission)
        if (launcher == null) {
            Log.e(TAG, "Launcher 未注册!")
            return false
        } else {
            launcher.launch(permission)
            Log.d(TAG, "requestPermission: 请求ing")
            return (checkPermission(context, arrayOf(permission)))
        }
    }

    //检查权限
    fun checkPermission(context:Context,target:Array<String>):Boolean {
        for (permission in target) {
            val result = ContextCompat.checkSelfPermission(context,permission)
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false
            }
        }
        return true
    }

    //注销启动器
    fun unRegisterLauncher(context: Context,permission: String) {
        if (ownerMap.containsKey(context) && ownerMap[context]!!.containsKey(permission)) {
            ownerMap[context]!!.remove(permission)
        }
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国标视频监控平台EasyCVR如何通过接口调用下载设备录像文件

安防监控系统国标GB28181协议EasyCVR视频监控平台采用了开放式的网络结构&#xff0c;平台可支持Windows/Linux(CentOS ubuntu)/国产麒麟系统&#xff0c;能在局域网、公网、专网等复杂的网络环境中&#xff0c;将场景中分散的海量网络监控设备进行统一接入与汇聚管理&#xff…

USB Cable导致连接识别不良

2根USB线&#xff0c;连接USB2RS232芯片&#xff0c;有根线能够识别&#xff0c;另外一根不能识别。 好的线识别如下&#xff1a; 另外一根就不能识别

GZ036 区块链技术应用赛项赛题第1套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷(1卷) 任 务 书 参赛队编号: 背景描述 随着消费需求的不断变化,消费者对食品安全的关注度越来越高,希望能参与食品供应链管理,让每个环节都透明化。但传统的供应链管理依靠纸张记录,保存数…

[自动驾驶算法][从0开始轨迹预测]:二、自动驾驶系统中常用的坐标系及相应的转换关系

自动驾驶中常见的坐标系与坐标转换 1. 传感器坐标系1.1 相机坐标系统1) 相机相关基础知识2) 相机各坐标系图像/像素坐标系相机坐标系像平面坐标系 3) 相机各坐标系之间的转换像平面坐标系到像素坐标系的转换&#xff08;平移缩放变换&#xff09;相机坐标系转像平面坐标系&…

Oracle基础查询介绍

1、oracle语句分为&#xff1a; DCL&#xff1a;数据控制语言&#xff0c;关键字有 grant、revoke 如&#xff1a;grant create table to test2; DDL&#xff1a;数据定义语言&#xff0c;关键字有 create、alter、drop、truncate 如&#xff1a;create table test1; DML&am…

接口测试用例设计 - 实战篇

一&#xff0e;接口测试流程 1&#xff0e;需求讨论 2&#xff0e;需求评审 3&#xff0e;场景设计 4&#xff0e;数据准备 5&#xff0e;执行 二&#xff0e;分析接口文档中哪些元素 1&#xff0e;接口名称 2&#xff0e;接口地址 3&#xff0e;支持格式 4&#xff0…

IDEA2023的激活与安装(全网最靠谱,最快捷的方式)

前言&#xff1a; 相信很多小伙伴已经开始了java的学习之旅&#xff0c;想要更快乐的学习当然少不了IDEA这个得力的开发工具软件。但是IDEA是付费的&#xff0c;免费版功能有太少&#xff0c;怎么才能既免费&#xff0c;又能使用上正式版呢&#xff01;当然还是激活啦&#xf…

【昕宝爸爸小模块】深入浅出之JDK21 中的虚拟线程到底是怎么回事(一)

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…

Leetcode22-旅行终点站(1436)

1、题目 给你一份旅游线路图&#xff0c;该线路图中的旅行线路用数组 paths 表示&#xff0c;其中 paths[i] [cityAi, cityBi] 表示该线路将会从 cityAi 直接前往 cityBi 。请你找出这次旅行的终点站&#xff0c;即没有任何可以通往其他城市的线路的城市。 题目数据保证线路…

【Macos系统】安装VOSviewer及使用VOSviewer教程!!以ESN网络的研究进行案例分析

【Macos系统】安装VOSviewer及使用VOSviewer教程 以ESN网络的研究进行案例分析 本文介绍如何安装和使用VOSviewer软件&#xff0c;并以ESN&#xff08;Echo State Network&#xff09;网络的研究为案例进行分析。利用VOSviewer对相关文献进行可视化分析&#xff0c;并深入了解…

最新可用GPT-3.5、GPT-4、Midjourney绘画、DALL-E3文生图模型教程【宝藏级收藏】

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

麒麟KYLINOS域名解析失败的修复方法

原文链接&#xff1a;麒麟KYLINOS域名解析失败的修复方法 hello&#xff0c;大家好啊&#xff01;今天我要给大家介绍的是在麒麟KYLINOS操作系统上修复域名解析的方法。在日常使用中&#xff0c;我们可能会遇到由于系统配置问题导致的域名解析失败&#xff0c;这在内网环境下尤…

世微AP5160宽电压 LED 降压型恒流芯片14-18V 3A 电源PCB线路

这是一款14-18V 3A 电流的PCB设计方案. 运用的是世微AP5160 电源驱动IC,这是一款效率高&#xff0c;稳定可靠的 LED 灯恒流驱动控制芯片&#xff0c;内置高精度比较器&#xff0c;固定 关断时间控制电路&#xff0c;恒流驱动电路等&#xff0c;特别适合大功率 LED 恒流驱动。 …

selenium模拟浏览器查询导出参考文献

通过使用Selenium和BeautifulSoup&#xff0c;在CNKI网站上&#xff0c;以"知识图谱"为关键词&#xff0c;通过自动化工具在搜索页面提取相关文章信息。点击清楚并全选进行文献导出&#xff0c;随后从导出页面和管理导出的页面提取参考文献。 浏览器及WebDriver下载…

集合框架(一)

集合体系概述 集合体系结构 Collection代表单列集合&#xff0c;每个元素&#xff08;数据&#xff09;只包含一个值。Map代表双列集合&#xff0c;每个元素包含两个值&#xff08;键值对&#xff09;。 Collection集合体系 Collection集合特点 List系列集合&#xff1a;添加…

主流进销存系统有哪些?企业该如何选择进销存系统?

主流进销存系统有哪些&#xff1f;企业该如何选择进销存系统&#xff1f; “永久免费”的软件&#xff0c;这个可能还真不太可能有。而且就算有&#xff0c;也只能说是相对免费。 因为要么就是数据存量有限&#xff0c;要么就是功能有限数据、信息都不保障&#xff0c;并且功…

最小矩阵宽度 - 华为OD统一考试

OD统一考试(C卷) 分值: 200分 题解: Java / Python / C++ 题目描述 给定一个矩阵,包含N*M个整数,和一个包含K个整数的数组。 现在要求在这个矩阵中找一个宽度最小的子短阵,要求子矩阵包含数组中所有的整数。 输入描述 第一行输入两个正整数 N, M 表示矩阵大小。 接下…

Go后端开发 -- 面向对象特征:结构体 继承 多态 interface

Go后端开发 – 面向对象特征&#xff1a;结构体 && 继承 && 多态 && interface 文章目录 Go后端开发 -- 面向对象特征&#xff1a;结构体 && 继承 && 多态 && interface一、Go的结构体1.结构体的声明和定义2.结构体传参 二、将…

嵌入式一开始要怎么学?

今日话题&#xff0c;嵌入式一开始要怎么学&#xff1f;废话不多说&#xff0c;我认为学习嵌入式编程无需观看视频&#xff0c;拥有好的文档比视频更有帮助。掌握一门编程语言是学好嵌入式的关键。现今有许多计算机编程语言可供选择&#xff0c;比如C语言和C等。如果你刚刚入门…

CDN(内容分发网络)和DNS(域名系统)的区别

CDN关注于提高网站的访问速度和性能&#xff0c;主要通过在全球范围内分布的服务器缓存内容来实现&#xff0c;而DNS则是将域名转换为IP地址的系统&#xff0c;是互联网上进行任何形式的数据交换和通信的基础。 CDN&#xff08;内容分发网络&#xff09; 目的&#xff1a;CDN的…