Android中BroadcastReceiver详解

3,412 阅读3分钟

BroadcastReceiver是什么?

Android app可以发送广播也可以接收系统或者其它app发送的广播,是发送/订阅的设计模式。这些广播被发送当重要的事件发生的时候。例如,安卓系统发送广播当各种各样系统事件发生的时候,比如手机启动了或者手机开始充电了。应用也可以发送自定义广播,例如通知其它应用一些他们可能感兴趣的东西,比如一些新的内容被下载了。

系统广播会在系统事件发生的时候被发送出来,比如当手机进入或者退出开发者选项的时候,所有订阅了系统广播的人都可以收到这个广播。

广播它自身是被包裹在了一个Intent里面,它是有一个唯一的标识的(例如android.intent.action.AIRPLANE_MODE)。这个Intent对象同时包含了一些其它的信息,在它的字段里面,飞行模式这个intent里面就包含了一个boolean的字段来表示飞行模式是开启还是关闭的。

BroadcastReceiver能用来做什么?

  1. 接收系统发送出的重要的广播(网络变化,开机,充电)
  2. app之间相互通信,相互拉活的手段
  3. app内部组建间通信的手段

BroadcastReceiver分为哪几类?

从不同的纬度区分,可能分为不同的类别。

  1. 系统广播/非系统广播
  2. 全局广播/本地广播
  3. 无序广播/有序广播/粘性广播

BroadcastReceiver怎么使用?

1. 注册广播

1.1 静态注册广播

<receiver android:name=".MyBroadcastReceiver"  android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
    </intent-filter>
</receiver>

1.2 动态注册广播

val br: BroadcastReceiver = MyBroadcastReceiver()
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply {
    addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
}
registerReceiver(br, filter)

2. 发送广播

Intent().also { intent ->
    intent.setAction("com.example.broadcast.MY_NOTIFICATION")
    intent.putExtra("data", "Notice me senpai!")
    sendBroadcast(intent)
}
sendBroadcast(Intent("com.example.NOTIFY"), Manifest.permission.SEND_SMS)
<uses-permission android:name="android.permission.SEND_SMS"/>

3. 接收广播

private const val TAG = "MyBroadcastReceiver"

class MyBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        StringBuilder().apply {
            append("Action: ${intent.action}\n")
            append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n")
            toString().also { log ->
                Log.d(TAG, log)
                Toast.makeText(context, log, Toast.LENGTH_LONG).show()
            }
        }
    }
}
<receiver android:name=".MyBroadcastReceiver"
          android:permission="android.permission.SEND_SMS">
    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>
var filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null )
<uses-permission android:name="android.permission.SEND_SMS"/>

BroadcastReceiver在不同版本的API中有哪些区别?

Android 9

从Android 9(API level 28)开始,NETWORK_STATE_CHANGED_ACTION广播不会携带用户的地理位置信息或者个人身份数据。 此外,当你的app运行在Android 9或者更高的手机上,系统的wifi广播也不会携带SSIDs, BSSIDs,连接信息或扫描结果。想获取以上信息,需要通过getConnectionInfo()来代替。

Android 8

从Android 8(API level 27)开始,系统加强了对静态广播的进一步限制,许多广播静态注册了也是收不到的,不过你可以采用动态注册的方式来接收这些广播。

Android 7

从Android 7(API level 24)开始,系统不会再发送ACTION_NEW_PICTURE,ACTION_NEW_VIDEO的广播。 同时从7.0开始app想要接受CONNECTIVITY_ACTION广播,需要通过动态注册广播的形式了,再通过静态广播注册的方式是不可以的了。

BroadcastReceiver发送广播和接收广播是怎样工作的?

看图吧,画了一幅图

广播流程图

BroadcastReceiver是怎么引发ANR的?

众所周知广播是会造成ANR的,造成ANR就是因为发送方将广播发送给AMS,然后AMS找有没有人注册,找到之后让它去执行,在执行开始之前AMS就开始为ANR进行耗时统计了,如果这个时候app进程已经存在,那么便把这个消息加入到消息队列中,等待调度,最后执行完成。如果app不存在,AMS会拉活我们的进程,然后我们的app会执行这个消息,所以如果我们被广播拉活,我们的启动时长也是会被统计到ANR的时间范围内的。

参考

  1. developer.android.com/guide/compo…