Skip to content

一、发送自定义广播的两种方式

1. 标准广播(Normal Broadcast)

  • 特点:异步发送,所有注册的接收器同时接收,无法拦截。
  • 适用场景:通知多个组件事件发生(如数据更新完成)。

示例代码

kotlin
// 创建 Intent,指定广播的 Action
val intent = Intent("com.example.MY_CUSTOM_ACTION").apply {
    // 附加数据(可选)
    putExtra("message", "Hello from broadcast!")
    putExtra("timestamp", System.currentTimeMillis())
}

// 发送标准广播
sendBroadcast(intent)

2. 有序广播(Ordered Broadcast)

  • 特点:同步发送,接收器按优先级顺序处理,可终止传播或修改数据。
  • 适用场景:需要链式处理广播(如权限验证链)。

示例代码

kotlin
val intent = Intent("com.example.ORDERED_ACTION").apply {
    putExtra("data", "Initial data")
}

// 发送有序广播
sendOrderedBroadcast(
    intent,
    null, // 权限(可选)
    object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            // 最终接收器处理结果(可选)
            val resultData = resultData
            Toast.makeText(context, "Final result: $resultData", Toast.LENGTH_SHORT).show()
        }
    },
    null, // Handler(默认主线程)
    0, // 初始代码
    null, // 初始数据
    null // 初始 Bundle
)

二、广播的显式与隐式发送

1. 隐式广播(Implicit Broadcast)

  • 定义:通过 Action 字符串匹配接收器,不指定目标组件。
  • 限制:Android 8.0 (API 26) 及以上,静态注册的接收器无法接收隐式广播(系统广播除外)。
  • 解决方案
    • 使用动态注册的接收器。
    • 发送显式广播(指定包名或组件)。

2. 显式广播(Explicit Broadcast)

  • 定义:直接指定目标组件(类名或包名)。
  • 适用场景:定向发送给特定应用或组件。

示例代码

kotlin
// 指定目标应用的包名
val intent = Intent("com.example.MY_CUSTOM_ACTION").apply {
    setPackage("com.example.targetapp") // 显式指定包名
    putExtra("secure_data", "123456")
}

// 发送广播(仅 com.example.targetapp 可接收)
sendBroadcast(intent)

三、携带复杂数据

1. 通过 Intent 附加数据

  • 支持类型:基本类型、String、Parcelable、Serializable 等。
  • 代码示例
    kotlin
    data class User(val name: String, val age: Int) : Parcelable {
        // Parcelable 实现(略)
    }
    
    val user = User("Alice", 30)
    val intent = Intent("com.example.USER_ACTION").apply {
        putExtra("user", user)
        putExtra("is_admin", true)
    }
    sendBroadcast(intent)

2. 通过 Bundle 附加数据

kotlin
val bundle = Bundle().apply {
    putString("key1", "value1")
    putInt("key2", 100)
}

val intent = Intent("com.example.BUNDLE_ACTION").apply {
    putExtras(bundle)
}
sendBroadcast(intent)

四、权限控制

1. 发送带权限的广播

  • 步骤
    1. 在发送方声明权限:
      xml
      <!-- AndroidManifest.xml -->
      <permission
          android:name="com.example.BROADCAST_PERMISSION"
          android:protectionLevel="signature" />
    2. 发送时附加权限:
      kotlin
      val intent = Intent("com.example.PROTECTED_ACTION")
      sendBroadcast(intent, "com.example.BROADCAST_PERMISSION")

2. 接收方声明权限

xml
<!-- 接收方的 AndroidManifest.xml -->
<uses-permission android:name="com.example.BROADCAST_PERMISSION" />

五、本地广播(已弃用,替代方案)

1. 旧方式(仅作参考)

kotlin
// 发送本地广播(使用 LocalBroadcastManager)
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)

2. 推荐替代方案

  • 使用 LiveDataFlow
    kotlin
    // 定义单例事件总线
    object EventBus {
        private val _events = MutableSharedFlow<String>()
        val events = _events.asSharedFlow()
    
        suspend fun sendEvent(event: String) {
            _events.emit(event)
        }
    }
    
    // 发送事件
    lifecycleScope.launch {
        EventBus.sendEvent("Custom Event")
    }
    
    // 接收事件
    lifecycleScope.launch {
        EventBus.events.collect { event ->
            Toast.makeText(context, "收到事件: $event", Toast.LENGTH_SHORT).show()
        }
    }

六、完整示例:发送与接收自定义广播

1. 发送方代码

kotlin
// 发送标准广播
fun sendCustomBroadcast() {
    val intent = Intent("com.example.MY_ACTION").apply {
        putExtra("data", "Hello from sender!")
    }
    sendBroadcast(intent)
}

// 发送有序广播并传递结果
fun sendOrderedBroadcastWithResult() {
    val intent = Intent("com.example.ORDERED_ACTION")
    sendOrderedBroadcast(
        intent,
        null,
        object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                val result = "Result: ${getResultData()}"
                Toast.makeText(context, result, Toast.LENGTH_SHORT).show()
            }
        },
        null,
        0,
        "Initial Data",
        null
    )
}

2. 接收方代码

kotlin
// 动态注册接收器
class MainActivity : AppCompatActivity() {
    private val receiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                "com.example.MY_ACTION" -> {
                    val data = intent.getStringExtra("data")
                    Toast.makeText(context, "收到广播: $data", Toast.LENGTH_SHORT).show()
                }
                "com.example.ORDERED_ACTION" -> {
                    // 修改有序广播结果
                    resultData = "Modified Data"
                    abortBroadcast() // 终止广播(可选)
                }
            }
        }
    }

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

        // 注册接收器
        val filter = IntentFilter().apply {
            addAction("com.example.MY_ACTION")
            addAction("com.example.ORDERED_ACTION")
            priority = 100 // 设置优先级(有序广播有效)
        }
        registerReceiver(receiver, filter)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(receiver)
    }
}

七、注意事项

  1. Android 8.0+ 限制

    • 静态注册的接收器无法接收隐式广播,需改用动态注册或显式广播。
    • 使用 setPackage() 指定目标包名绕过限制:
      kotlin
      intent.setPackage("com.example.targetapp")
  2. 性能优化

    • 避免在广播中传递大数据(如图片),改用文件路径或标识符。
    • 使用 LocalBroadcastManager 的替代方案(如 LiveData)减少跨进程开销。
  3. 安全性

    • 敏感数据通过权限或应用签名保护。
    • 使用 Intent.setPackage() 或组件类名限制接收范围。
  4. 生命周期管理

    • 动态注册的接收器需在组件销毁时取消注册。
    • 静态注册的接收器在 onReceive() 中避免耗时操作(主线程限制)。

通过合理设计广播逻辑,可以实现灵活且高效的组件通信,同时确保应用的安全性和兼容性。