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
英文地址,請注明出處:http://en.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;前人在云服務器上…