Android BroadcastReceiver - tenji/ks GitHub Wiki
Android App 可以发送广播也可以接收系统或者其它 App 发送的广播,是发送/订阅的设计模式。这些广播被发送当重要的事件发生的时候。例如,当各种各样系统事件发生的时候安卓系统发送广播,比如手机启动了或者手机开始充电了。应用也可以发送自定义广播,例如通知其它应用一些他们可能感兴趣的东西,比如一些新的内容被下载了。
系统广播会在系统事件发生的时候被发送出来,比如当手机进入或者退出开发者选项的时候,所有订阅了系统广播的人都可以收到这个广播。
广播它自身是被包裹在了一个 Intent 里面,它是有一个唯一的标识的(例如 android.intent.action.AIRPLANE_MODE
)。这个 Intent 对象同时包含了一些其它的信息,在它的字段里面,飞行模式这个 intent 里面就包含了一个 boolean 的字段来表示飞行模式是开启还是关闭的。
- 接收系统发送出的重要的广播(网络变化,开机,充电);
- App 之间相互通信,相互拉活的手段;
- App 内部组建间通信的手段。
又称无序广播,这种广播完全是异步的,所有与广播 Intent 匹配的 BroadcastReceiver,都可以收到这条广播,并且不分先后顺序,视为同时收到,通过 Context.sendBroadcast() 方法发送。这种广播的效率比较高,但缺点是接收器不能将处理结果传递给下一个接收器,并且无法在中途终止广播。
Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action
intent.setAction("test");
//发送广播
sendBroadcast(intent);
这是一种同步执行的广播,通过 Context.sendOrderedBroadcast() 方法发送,这种广播发出后,通过 receiver 的 intent-filter 中的 android:priority 属性来设置优先级,优先级从-1000~1000,数越大,优先级越高,使用 setResult() 方法把结果传递给下一个接收者,通过 getResult() 方法获取上一个接收者传递过来的结果,并可以通过 abortBroadcast() 方法丢弃该广播,使该广播不再传递给下一个接收者。
粘性广播通过 Context.sendStickBroadcast() 方法来发送,用此方法发送的广播会一直滞留,当有匹配此广播的接收器被注册后,该广播接收器就会收到此广播。使用此广播时,需要获得 BROADCAST_STICKY 权限。(在 android 5.0/api 21后不再推荐使用)
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
Android 系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相应的系统广播。如:开启启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的 intent-filter,其中主要包括具体的 action,系统广播发出后,将被相应的 BroadcastReceiver 接收。系统广播在系统内部当特定事件发生时,有系统自动发出。
以上广播都属于全局广播,发出去的广播,只要有匹配的接收者,就可以收到广播。这样一来会造成一些问题,一是消耗性能,二是容易引起安全性的问题,为了能够简单的解决这方面的问题,Android 引入了一套广播本地广播机制,使用该机制发出的广播只能够在本应用内部进行传递,并且广播接收器也只能接收来自本应用发出的广播。
-
静态注册(常驻)
静态注册就是在 AndroidManifest 中注册 BroadcastReceiver,并指定它所接收的广播种类,如下面配置的 MyReceiver 用来接收开机广播:
<receiver android:name=".MyReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
-
动态注册(非常驻)
@Override protected void onResume() { super.onResume(); mReceiver = new MyReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("test"); registerReceiver(mReceiver, intentFilter); // 注册广播接收器 } @Override protected void onPause() { unregisterReceiver(mReceiver); // 注销广播接收器 super.onPause(); }
本文用到的 BroadcastReceiver:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
待更新...
待更新...
从 Android 9 (API level 28) 开始,NETWORK_STATE_CHANGED_ACTION
广播不会携带用户的地理位置信息或者个人身份数据。此外,当你的 App 运行在 Android 9 或者更高的手机上,系统的 Wifi 广播也不会携带 SSIDs, BSSIDs,连接信息或扫描结果。想获取以上信息,需要通过 getConnectionInfo()
来代替。
从 Android 8 (API level 27) 开始,系统加强了对静态广播的进一步限制,许多广播静态注册了也是收不到的,不过你可以采用动态注册的方式来接收这些广播。
从 Android 7 (API level 24) 开始,系统不会再发送 ACTION_NEW_PICTURE
, ACTION_NEW_VIDEO
的广播。同时从7.0开始 App 想要接受 CONNECTIVITY_ACTION
广播,需要通过动态注册广播的形式了,再通过静态广播注册的方式是不可以的了。
待更新...
众所周知广播是会造成 ANR 的,造成 ANR 就是因为发送方将广播发送给 AMS (ActivityManagerService),然后 AMS 找有没有人注册,找到之后让它去执行,在执行开始之前 AMS 就开始为 ANR 进行耗时统计了,如果这个时候 App 进程已经存在,那么便把这个消息加入到消息队列中,等待调度,最后执行完成。如果 App 不存在,AMS 会拉活我们的进程,然后我们的 App 会执行这个消息,所以如果我们被广播拉活,我们的启动时长也是会被统计到 ANR 的时间范围内的。