11. 广播
11.1 广播机制
- 标准广播-normal broadcasts
是一种完全异步执行的广播,在广播发出后,所有的BroadcastReceiver几乎在同一时刻收到这条广播消息,没有先后顺序。效率高,无法被截断。
- 有序广播-ordered broadcasts
是一种同步执行广播,在广播发出后,同一时刻只会有一个BroadcastReceiver能够接受到这条广播,当这个BroadcastReceiver中逻辑执行完后,广播才会继续传递。所以是有先后顺序的,优先级高先收到广播消息,并且前面的BroadcastReceiver能够截断正在传递的广播。
BroadcastReceiver中是不允许开启线程的。当onReceive()方法运行较长时间没有结束时,程序会出现错误。
11.2 注册广播的两种方式
- 静态注册:AndroidManifest.xml中的receiver注册
intent-filter、action
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
常驻广播,应用程序关闭后,如果有注册的广播来,程序也会被系统调用自动运行。
- 动态注册:代码中调用
registerReceiver(),记得适时销毁
val intentFilterMyBroadcast = IntentFilter()
intentFilterMyBroadcast.addAction("$packageName.MY_BROADCAST")
myBroadcastReceiver = MyBroadcastReceiver()
registerReceiver(myBroadcastReceiver, intentFilter)
不是常驻广播,广播跟随程序的声明周期。
11.3 接收系统广播
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
lateinit var timeChangeReceiver: TimeChangeReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
val intentFilter = IntentFilter()
intentFilter.addAction("android.intent.action.TIME_TICK")
timeChangeReceiver = TimeChangeReceiver()
registerReceiver(timeChangeReceiver, intentFilter)
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(timeChangeReceiver)
}
}
class TimeChangeReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show()
}
}
当系统时间发生变化时,每隔一分钟,系统会发送一条android.intent.action.TIME_TICK的广播。
收到广播,触发onReceive中的代码。
11.4 发送自定义广播
新建自定义广播
新建广播时:
- Exported:是否允许这个BroadcastReceiver接收本程序以外的广播
- Enabled:是否启用这个BroadcastReceiver
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// This method is called when the BroadcastReceiver is receiving an Intent broadcast
val p = intent.`package`
val data = intent.getStringExtra("key1")
Log.d("MyBroadcastReceiver", "p: $p; data: $data")
Toast.makeText(context, "received in MyBroadcastReceiver", android.widget.Toast.LENGTH_SHORT).show()
}
}
AndroidManifest.xml中的receiver注册intent-filter、action
action android:name 类似于Swift的Notification.Name
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
Activity中发送广播
binding.button1.setOnClickListener {
val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
intent.setPackage(packageName)
intent.putExtra("key1", "value1")
sendBroadcast(intent)
}
11.5 发送有序广播
新建一个AnotherBroadcastReceiver广播
class AnotherBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
Toast.makeText(context, "received in AnotherBroadcastReceiver", android.widget.Toast.LENGTH_SHORT).show()
}
}
Activity中发送sendOrderedBroadcast
binding.button1.setOnClickListener {
val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
intent.setPackage(packageName)
intent.putExtra("key1", "value1")
sendOrderedBroadcast(intent, null)
}
设置优先级android:priority,谁高谁先接收到
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="0">
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
可以中止广播传递 abortBroadcast()
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// This method is called when the BroadcastReceiver is receiving an Intent broadcast
val p = intent.`package`
val data = intent.getStringExtra("key1")
Log.d("MyBroadcastReceiver", "p: $p; data: $data")
Toast.makeText(context, "received in MyBroadcastReceiver", android.widget.Toast.LENGTH_SHORT).show()
abortBroadcast()
}
}