一、什么是Broadcast
在安卓系统中,广播是一种通信机制,用于在各种组件之间传递消息。广播允许应用程序的不同部分或不同应用程序之间进行通信。广播主要用于通知其它组件特定事件的发生。例如设备启动、网络连接状态更改、电池电量变化等。
二、广播概述
广播在日常生活中较为常见。例如每个教室均有一个音响,当上课/下课时,该音响就会接收到一个广播信号,开始广播上课/下课铃。
与之类似,安卓中的广播用于从广播发送者向各个广播接收者发送消息,是安卓四大组件之一。安卓广播是实现跨程序或程序内部通信的重要机制。广播允许应用程序的不同部分或不同应用程序之间发送和接收消息,以便在特定事件发生时进行响应或执行相应的操作。因此,通过广播可以实现安卓的线程/进程间通信。
广播组件主要由两个角色组成:
1.广播发送者(Broadcast Sender):负责发送广播消息。发送者可以是应用程序的任何组件,如活动(Activity)、服务(Service)。
2.广播接收者(Broadcast Receiver):负责接收广播消息并对其进行响应。接收者需要注册到系统中以便在特定事件发生时接收广播。
广播接收者订阅感兴趣的广播(通知)。当广播发送者发出相应的广播(通知)时,所订阅的接收者就会收到相应的数据,并进行业务处理。具体来说,其实现方式如下:
1)广播接收者通过Binder在Activity Manager Service(AMS)中注册(订阅感兴趣的广播)
2)广播发送者通过Binder向AMS发送广播
3)AMS通过(Intent Filter/Permission)查找注册(订阅)该广播的接收者,并把消息送入消息队列
4)消息抵达接收者,触发接收者的on Receive回调。可以在该回调中对获取的广播数据进行处理
广播组件的使用场景广泛,包括但不限于:
单个APP的单个组件(单个或多个线程)
单个APP多个组件(单进程)
单个APP不同进程的组件(多进程)
多个APP之间通信
安卓系统与某个APP进行通信
可见,广播机制非常适用于不同进程之间的通信
三、广播接收者
1.广播接收者的创建
(1)通过Android Studio中的New -> Other -> Broadcast Receiver来创建 在对应的包右击(例如默认的Main Activity所在的包),依次如下创建。
on Receive用于接收广播消息。可见,广播消息依然是一种Intent
通过这种方法创建的广播接收者,会被自动注册到配置文件中
(2)也可以手动实现广播接收者 简单来说,其步骤如下:
a.创建一个类,继承Broadcast Receiver
b.实现其中的on Receiver回调
2.注册(订阅)广播事件
(1)静态注册(安卓8.0后对该方法进行了限制,不推荐)
(2)动态注册
3.静态注册
静态注册方法涉及 intent-filter。隐式 Intent 不直接指定目标组件的类名,而是通过指定动作(Action)、数据类型(Data)和/或类别(Category)来描述要执行的操作,系统会根据这些信息选择合适的组件来响应 Intent。
因此,静态注册方法也是在配置文件中,通过intent-filter为广播接收器注册所要接收的事件。例如,接收时区变化的系统广播
首先在配置文件中为该接收器进行静态注册
然后在对应类的onReceive方法中处理接收到该广播后的逻辑
之后修改手机的时区。默认时区是中国时区,这里随便修改成别的时区,观察logcat的结果
广播接收者的静态注册较为简单,且应用退出后依然可以接受到广播消息。因此,考虑到权限安全以及电池功耗等问题,安卓8.0后的版本无法通过静态注册接收大部分系统广播。
4.动态注册
现在大部分的广播接收者采用动态注册的方式。下面以电池电量变化广播为例。 首先,无论是静态注册还是动态注册
首先需要创建一个广播接收器类
ReceiverDemo02.kt
package com.example.review04
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.BatteryManager
class ReceiverDemo02 : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
TODO("ReceiverDemo02.onReceive() is not implemented")
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL,-1)
println("当前电量:${level}")
}
}
接下来,在一个Activity的on Create回调中动态地为该接收器注册电量变化广播
Demo01Activity.kt
package com.example.review04
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.PersistableBundle
class Demo01Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_demo01)
}
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
val batteryReceiver = ReceiverDemo02()
registerReceiver(batteryReceiver,intentFilter)
}
}
修改安卓设备的电量,模拟器中可通过图示方法。观察logcat的输出
我们实现了一个简单的动态注册的广播接收器。但是当Activity在后台运行时,该接收器依然会接收广播,且无法关闭。一个更加合理的动态注册代码如下:
Demo02Activity.kt
package com.example.review04
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class Demo02Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_demo02)
}
private lateinit var batteryReceiverDemo02: ReceiverDemo02
override fun onResume() {
super.onResume()
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
batteryReceiverDemo02 = ReceiverDemo02()
registerReceiver(batteryReceiverDemo02,intentFilter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(batteryReceiverDemo02)
}
}
对比动态注册与静态注册:
四、自定义广播
广播接收者接收时区变化和电量变化的广播,这些都是系统发出的广播。当然也可以自行编写代码,发送自定义广播,实现更加复杂的功能。
实现自定义广播较为简单,只需要通过sendBroadcast方法发送广播即可
举例:点击按钮,发送自定义广播,并接收该广播,打印消息
activity_demo03.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Demo03Activity">
<Button
android:id="@+id/btn_BC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
Demo03Activity.kt
package com.example.review04
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
class Demo03Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_demo03)
val btnBC = findViewById<Button>(R.id.btn_BC)
btnBC.setOnClickListener {
val intent = Intent()
intent.action = "CUSTOM_BROADCAST"
sendBroadcast(intent)
}
}
override fun onResume() {
super.onResume()
val intentFilter = IntentFilter()
intentFilter.addAction("CUSTOM_BROADCAST")
val customReceiverDemo03 = ReceiverDemo03()
registerReceiver(customReceiverDemo03,intentFilter)
}
}
ReceiverDemo03.kt
package com.example.review04
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class ReceiverDemo03 : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
println("接收到自定义广播")
println(intent.action)
}
}
运行后查看:
自定义广播的用途主要包括以下几个方面:
1. 组件间通信 自定义广播允许应用内的不同组件(如Activity、Service、Fragment)进行通信。例如Service可以发送广播通知Activity某个任务已完成,Activity接收到广播后更新UI。
2. 解耦 通过广播机制,可以使发送者和接收者之间的耦合度降低。发送广播的组件不需要知道接收广播的具体组件,实现了松耦合设计,提高了代码的模块化和可维护性。
3. 跨进程通信 在某些情况下,自定义广播可以用于跨进程通信。例如,当应用分为多个进程运行时,可以通过自定义广播在不同进程之间传递消息。
五、广播的类型
安卓中的广播类型主要有如下两种:
标准广播(Normal Broadcasts)(无序广播):标准广播/无序广播是完全异步的。所有接收器几乎同时接收广播,无法控制广播接收的顺序。该广播使用sendBroadcast()方法发送。
有序广播(Ordered Broadcasts):有序广播是同步的,一个接一个地按顺序传递广播,接收器可以决定是否将广播传递给下一个接收器。接收器可以修改广播数据或者截断广播的传播。有序广播使用sendOrderedBroadcast()方法发送。
1.无序广播:使用sendBroadcast()方法发送即可。
2.有序广播:首先,编写两个广播接收者
为两个接收器分别注册广播事件:
发送有序广播:
sendOrderBroadcast中第二个参数用于指定哪些接收者可以接收该广播,一般设为null即可
运行结果:
考虑到难以确保程序以合适的顺序注册各个接收者。因此可以为各个接收者设置优先级,实现规定的顺序。