Android Kotlin 动态注册 Broadcast 的完整封装方案

在 Kotlin 中封装动态注册的 Broadcast 可以让你更优雅地管理广播的注册和注销,避免内存泄漏。下面是一个完整的封装方案:

  1. 基础封装类
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Handler
import android.os.Looperclass DynamicBroadcastManager private constructor() {private val receivers = mutableMapOf<Context, MutableList<BroadcastReceiver>>()private val intentFilters = mutableMapOf<BroadcastReceiver, IntentFilter>()companion object {@Volatileprivate var instance: DynamicBroadcastManager? = nullfun getInstance(): DynamicBroadcastManager {return instance ?: synchronized(this) {instance ?: DynamicBroadcastManager().also { instance = it }}}}/*** 注册广播接收器* @param context 上下文* @param receiver 广播接收器* @param filter 意图过滤器* @param permission 权限(可选)* @param handler Handler(可选)*/fun registerReceiver(context: Context,receiver: BroadcastReceiver,filter: IntentFilter,permission: String? = null,handler: Handler? = null) {try {context.registerReceiver(receiver, filter, permission, handler)// 保存注册信息if (!receivers.containsKey(context)) {receivers[context] = mutableListOf()}receivers[context]?.add(receiver)intentFilters[receiver] = filter} catch (e: Exception) {e.printStackTrace()}}/*** 注销广播接收器* @param context 上下文* @param receiver 广播接收器*/fun unregisterReceiver(context: Context, receiver: BroadcastReceiver) {try {context.unregisterReceiver(receiver)receivers[context]?.remove(receiver)intentFilters.remove(receiver)// 如果该context没有其他接收器,移除记录if (receivers[context]?.isEmpty() == true) {receivers.remove(context)}} catch (e: Exception) {e.printStackTrace()}}/*** 注销指定上下文的所有广播接收器* @param context 上下文*/fun unregisterAllReceivers(context: Context) {receivers[context]?.let { receiverList ->val copyList = receiverList.toList() // 创建副本避免并发修改copyList.forEach { receiver ->unregisterReceiver(context, receiver)}}}/*** 获取指定接收器的IntentFilter* @param receiver 广播接收器*/fun getIntentFilter(receiver: BroadcastReceiver): IntentFilter? {return intentFilters[receiver]}/*** 检查接收器是否已注册* @param context 上下文* @param receiver 广播接收器*/fun isReceiverRegistered(context: Context, receiver: BroadcastReceiver): Boolean {return receivers[context]?.contains(receiver) ?: false}
}
  1. 使用示例

基本使用方式

// 定义广播Action常量
object BroadcastActions {const val NETWORK_CHANGED = "android.net.conn.CONNECTIVITY_CHANGE"const val CUSTOM_ACTION = "com.example.app.CUSTOM_ACTION"
}// 创建广播接收器
class NetworkChangeReceiver : BroadcastReceiver() {override fun onReceive(context: Context?, intent: Intent?) {when (intent?.action) {BroadcastActions.NETWORK_CHANGED -> {// 处理网络变化handleNetworkChange(context, intent)}BroadcastActions.CUSTOM_ACTION -> {// 处理自定义广播handleCustomAction(context, intent)}}}private fun handleNetworkChange(context: Context?, intent: Intent?) {// 网络变化处理逻辑}private fun handleCustomAction(context: Context?, intent: Intent?) {// 自定义广播处理逻辑}
}// 在Activity或Fragment中使用
class MainActivity : AppCompatActivity() {private lateinit var networkReceiver: NetworkChangeReceiverprivate val broadcastManager = DynamicBroadcastManager.getInstance()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 初始化广播接收器networkReceiver = NetworkChangeReceiver()// 注册广播registerBroadcasts()}private fun registerBroadcasts() {// 创建IntentFilterval filter = IntentFilter().apply {addAction(BroadcastActions.NETWORK_CHANGED)addAction(BroadcastActions.CUSTOM_ACTION)}// 注册广播接收器broadcastManager.registerReceiver(this, networkReceiver, filter)}override fun onDestroy() {super.onDestroy()// 注销广播接收器broadcastManager.unregisterAllReceivers(this)}// 发送自定义广播private fun sendCustomBroadcast() {val intent = Intent(BroadcastActions.CUSTOM_ACTION).apply {putExtra("data", "Hello from MainActivity!")}sendBroadcast(intent)}
}
  1. 更高级的封装 - 使用 DSL 方式
class BroadcastBuilder {private val actions = mutableListOf<String>()private var permission: String? = nullprivate var handler: Handler? = nullfun action(action: String) = apply { actions.add(action) }fun actions(vararg actions: String) = apply { this.actions.addAll(actions) }fun permission(permission: String?) = apply { this.permission = permission }fun handler(handler: Handler?) = apply { this.handler = handler }fun build(): IntentFilter {return IntentFilter().apply {actions.forEach { addAction(it) }}}
}// DSL扩展函数
inline fun broadcastReceiver(context: Context,crossinline onReceive: (Context, Intent) -> Unit
): BroadcastReceiver {return object : BroadcastReceiver() {override fun onReceive(context: Context, intent: Intent) {onReceive(context, intent)}}
}// 使用DSL方式注册广播
fun DynamicBroadcastManager.registerWithDSL(context: Context,receiver: BroadcastReceiver,builder: BroadcastBuilder.() -> Unit
) {val broadcastBuilder = BroadcastBuilder().apply(builder)val filter = broadcastBuilder.build()registerReceiver(context, receiver, filter, broadcastBuilder.permission, broadcastBuilder.handler)
}

DSL 使用示例

class MainActivity : AppCompatActivity() {private val broadcastManager = DynamicBroadcastManager.getInstance()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 使用DSL方式注册广播val receiver = broadcastReceiver(this) { context, intent ->when (intent.action) {BroadcastActions.NETWORK_CHANGED -> {// 处理网络变化}BroadcastActions.CUSTOM_ACTION -> {val data = intent.getStringExtra("data")// 处理数据}}}broadcastManager.registerWithDSL(this, receiver) {action(BroadcastActions.NETWORK_CHANGED)action(BroadcastActions.CUSTOM_ACTION)permission(android.Manifest.permission.ACCESS_NETWORK_STATE)handler(Handler(Looper.getMainLooper()))}}override fun onDestroy() {super.onDestroy()broadcastManager.unregisterAllReceivers(this)}
}
  1. 生命周期感知的封装
class LifecycleAwareBroadcastManager(private val context: Context,private val lifecycle: Lifecycle
) : DefaultLifecycleObserver {private val receivers = mutableListOf<Pair<BroadcastReceiver, IntentFilter>>()private val broadcastManager = DynamicBroadcastManager.getInstance()init {lifecycle.addObserver(this)}fun registerReceiver(receiver: BroadcastReceiver, filter: IntentFilter) {receivers.add(receiver to filter)if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {broadcastManager.registerReceiver(context, receiver, filter)}}@OnLifecycleEvent(Lifecycle.Event.ON_START)fun onStart() {receivers.forEach { (receiver, filter) ->broadcastManager.registerReceiver(context, receiver, filter)}}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)fun onStop() {receivers.forEach { (receiver, _) ->broadcastManager.unregisterReceiver(context, receiver)}}@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)fun onDestroy() {lifecycle.removeObserver(this)receivers.clear()}
}

生命周期感知使用示例

class MainActivity : AppCompatActivity() {private lateinit var lifecycleAwareManager: LifecycleAwareBroadcastManageroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)lifecycleAwareManager = LifecycleAwareBroadcastManager(this, lifecycle)val receiver = broadcastReceiver(this) { context, intent ->// 处理广播}val filter = IntentFilter(BroadcastActions.NETWORK_CHANGED)lifecycleAwareManager.registerReceiver(receiver, filter)}
}

主要特点

  1. 单例管理:确保广播管理器的唯一实例
  2. 自动清理:提供统一的注销方法,避免内存泄漏
  3. 灵活注册:支持多种注册方式和参数配置
  4. DSL支持:提供更优雅的API使用方式
  5. 生命周期感知:与Android生命周期无缝集成
  6. 错误处理:包含异常捕获,提高稳定性

这种封装方式可以帮助你更好地管理动态注册的广播,避免常见的内存泄漏问题,并提供更简洁的API接口。

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

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

相关文章

VGG改进(8):融合Self-Attention的CNN架构

1. 自注意力机制简介自注意力机制是Transformer架构的核心组件&#xff0c;它能够计算输入序列中每个元素与其他所有元素的相关性。与CNN的局部感受野不同&#xff0c;自注意力机制允许模型直接建立远距离依赖关系&#xff0c;从而捕获全局上下文信息。在计算机视觉中&#xff…

ES6 面试题及详细答案 80题 (33-40)-- Symbol与集合数据结构

《前后端面试题》专栏集合了前后端各个知识模块的面试题&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

PG-210-HI 山洪预警系统呼叫端:筑牢山区应急预警 “安全防线”

在山洪灾害多发的山区&#xff0c;及时、准确的预警信息传递是保障群众生命财产安全的关键。由 PG-210-HI 型号构成的山洪预警系统呼叫端主机&#xff0c;凭借其全面的功能、先进的特性与可靠的性能&#xff0c;成为连接管理员与群众的重要应急枢纽&#xff0c;为山区构建起一道…

研学旅游产品设计实训室:赋能产品落地,培养实用人才

1. 研学旅游产品设计实训室的定位与功能 研学旅游产品设计实训室是专门为学生提供研学课程与产品开发、模拟设计、项目推演、成果展示等实践活动的教学空间。该实训室应支持以下功能&#xff1a; 研学主题设计与目标制定&#xff1b; 课程内容与学习方法的选择与整合&#xf…

4215kg轻型载货汽车变速器设计cad+设计说明书

第一章 前言 3 1.1 变速器的发展环绕现状 3 1.2 本次设计目的和意义 4 第二章 传动机构布置方案分析及设计 5 2.1 传动机构结构分析与类型选择 5 2.2变速器主传动方案的选择 5 2.3 倒档传动方案 6 2..4 变速器零、部件结构方案设计 6 2.4.1 齿轮形式 …

9月10日

TCP客户端代码#include<myhead.h> #define SER_IP "192.168.108.179" //服务器&#xff49;&#xff50;地址 #define SER_PORT 8888 //服务器端口号 #define CLI_IP "192.168.108.239" //客户端&#xff49;&#xff50;地址 …

案例开发 - 日程管理 - 第七期

项目改造&#xff0c;进入 demo-schedule 项目中&#xff0c;下载 pinia 依赖在 main.js 中开启 piniaimport { createApp } from vue import App from ./App.vue import router from ./router/router.js import {createPinia} from pinialet pinia createPinia() const app …

infinityfree 网页连接内网穿透 localtunnel会换 还是用frp成功了

模型库首页 魔搭社区 fatedier/frp: A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet. 我尝试用本机ipv6&#xff0c;失败了 配置文件 - ChmlFrp 香港2才能用 只支持https CNAME解析 | 怊猫科技 | 文档 How to create …

批量更新数据:Mybatis update foreach 和 update case when 写法及比较

在平常的开发工作中&#xff0c;我们经常需要批量更新数据&#xff0c;业务需要每次批量更新几千条数据&#xff0c;采用 update foreach 写法的时候&#xff0c;接口响应 10s 左右&#xff0c;优化后&#xff0c;采用 update ... case when 写法&#xff0c;接口响应 2s 左右。…

Java基础篇04:数组、二维数组

1 数组 数组是一个数据容器&#xff0c;可用来存储一批同类型的数据。 1.1 数组的定义方式 静态初始化 数据类型[][] 数组名 {元素1&#xff0c;元素2&#xff0c;元素3}; string[][] name {"wfs","jsc","qf"} 动态初始化 数据类型[][] 数组名…

unity开发类似个人网站空间

可以用 Unity 开发 “个人网站空间” 类工具&#xff0c;但需要结合其技术特性和适用场景来判断是否合适。以下从技术可行性、优势、局限性、适用场景四个方面具体分析&#xff1a;一、技术可行性Unity 本质是游戏引擎&#xff0c;但具备开发 “桌面应用” 和 “交互内容” 的能…

SDK游戏盾如何实现动态加密

SDK游戏盾的动态加密体系通过​​密钥动态管理、多层加密架构、协议混淆、AI自适应调整及设备绑定​​等多重机制协同作用&#xff0c;实现对游戏数据全生命周期的动态保护&#xff0c;有效抵御中间人攻击、协议破解、重放攻击等威胁。以下从核心技术与实现逻辑展开详细说明&am…

TensorFlow平台介绍

什么是 TensorFlow&#xff1f; TensorFlow 是一个由 Google Brain 团队 开发并维护的 开源、端到端机器学习平台。它的核心是一个强大的数值计算库&#xff0c;特别擅长于使用数据流图来表达复杂的计算任务&#xff0c;尤其适合大规模机器学习和深度学习模型的构建、训练和部署…

TENGJUN防水TYPE-C连接器:立贴结构与IPX7防护的精密融合

在户外电子、智能家居、车载设备等对连接可靠性与空间适配性要求严苛的场景中&#xff0c;连接器不仅是信号与电力传输的“桥梁”&#xff0c;更需抵御潮湿、粉尘等复杂环境的侵蚀。TENGJUN防水TYPE-C连接器以“双排立贴”为核心设计&#xff0c;融合锌合金底座、精准尺寸控制与…

Spring Boot + Vue 项目中使用 Redis 分布式锁案例

加锁使用命令&#xff1a;set lock_key unique_value NX PX 1000NX:等同于SETNX &#xff0c;只有键不存在时才能设置成功PX&#xff1a;设置键的过期时间为10秒unique_value&#xff1a;一个必须是唯一的随机值&#xff08;UUID&#xff09;&#xff0c;通常由客户端生成…

微信小程序携带token跳转h5, h5再返回微信小程序

需求: 在微信小程序内跳转到h5, 浏览完后点击返回按钮再返回到微信小程序中 微信小程序跳转h5: 微信小程序跳转h5,这个还是比较简单的, 但要注意细节 一、微信小程序代码 1.新建跳转h5页面, 新建文件夹,新建page即可 2.使用web-view标签 wxml页面 js页面 到此为止, 小程序…

【机器学习】通过tensorflow实现猫狗识别的深度学习进阶之路

【机器学习】通过tensorflow实现猫狗识别的深度学习进阶之路 简介 猫狗识别作为计算机视觉领域的经典入门任务&#xff0c;不仅能帮助我们掌握深度学习的核心流程&#xff0c;更能直观体会到不同优化策略对模型性能的影响。本文将从 “从零搭建简单 CNN” 出发&#xff0c;逐步…

异步处理(前端面试)

Promise 1&#xff1a;使用promise原因 了解回调地狱【什么是回调地狱】 1&#xff1a;回调地狱是异步获取结果后&#xff0c;为下一个异步函数提供参数&#xff0c;层层回调嵌入回调 2&#xff1a;导致回调层次很深&#xff0c;代码维护特别困难 3&#xff1a;在没有ES6时&…

3种XSS攻击简单案例

1、接收cookie端攻击机上用python写个接收web程序flask from flask import Flask, request, Responseapp Flask(__name__)app.route(/) def save_cookie():cookie request.args.get(cookie, )if cookie:with open(/root/cookies.txt, a) as f:f.write(f"{cookie}\n"…

Docker 部署生产环境可用的 MySQL 主从架构

简介跨云服务器一主一从&#xff0c;可以自己按照逻辑配置多个从服务器 假设主服务器ip: 192.168.0.4 从服务器ip&#xff1a;192.168.0.5 系统 CentOS7.9 &#xff08;停止维护了&#xff0c;建议大家用 Ubuntu 之类的&#xff0c;我这个没办法&#xff0c;前人在云服务器上…