Broadcast 基础与使用
Broadcast 基础与使用
广播简介
系统会在发生各种系统事件时自动发送广播,例如当系统进入和退出飞行模式时。系统广播会被发送给所有同意接收相关事件的应用。
广播消息本身会被封装在一个 Intent 对象中,该对象的操作字符串会标识所发生的事件(例如 android.intent.action.AIRPLANE_MODE)。该 Intent 可能还包含绑定到其 extra 字段中的附加信息。例如,飞行模式 intent 包含布尔值 extra 来指示是否已开启飞行模式。
广播的定义
在 Android 中,Broadcast 是一种在应用程序之间传输信息的机制,要发送的广播内容是一个 Intent,这个 Intent 中可以携带我们要传送的数据。(数据小于1MB)
广播的用途
- 广播实现了不同程序之间的信息传输与共享,只要和发送广播的 action 相同的接收者,都能接收到这个广播。典型的应用就是 android 自带的短信,电话等等广播,只要我们实现了他们的 action 的广播,那么我们就能接收他们的数据了,以便做出一些处理。比如说拦截系统短信,拦截骚扰电话等。
- 作为通知的作用,比如在 Service 中要通知主程序、更新主程序的 UI 等,因为 Service 是没有界面的,所以不能直接获得主程序中的控件,这样我们就只能在主程序中实现一个广播接收者专门用来接收service发过来的数据和通知了。
广播的使用场景
- 同一app内部的同一组件内的消息通信(单个或多个线程之间)(可用handler解决);
- 同一app内部的不同组件之间的消息通信(单个进程)(可用EventBus);
- 同一app具有多个进程的不同组件之间的消息通信;
- 不同app之间的组件之间的消息通信;
- Android系统在特定情况下与App之间的消息通信。
广播主要的种类
普通广播Normal Broadcast:异步执行的广播,所有接收者在同一时刻收到这条广播消息。效率高,没有先后顺序,无法截断。属于全局广播。调用 sendBroadcast()发送,最常用的广播。
有序广播Ordered Broadcast:同步执行的广播,发出去的广播会被广播接收者按照顺序接收,广播接收者按照Priority属性值从大-小排序,Priority属性相同者,动态注册的广播优先,广播接收者还可以选择对广播进行截断和修改。调用sendOrderedBroadcast()发送。
本地广播Local Broadcast:App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高。对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册。调用sendBroadcast发送。
对应的广播action定义
Android SDK 中的 BROADCAST_ACTIONS.TXT 文件。每个广播操作都有一个与之关联的常量字段。例如,常量 ACTION_AIRPLANE_MODE_CHANGED 的值为 android.intent.action.AIRPLANE_MODE。每个广播操作的文档都可以在关联的常量字段中找到。
静态注册接收广播
- 在应用清单中指定 receiver 元素。
<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>
- 创建子类
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(Context context, Intent intent) {
StringBuilder sb = new StringBuilder();
sb.append("Action: " + intent.getAction() + "\n");
sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
String log = sb.toString();
Log.d(TAG, log);
Toast.makeText(context, log, Toast.LENGTH_LONG).show();
}
}
动态上下文注册的接收器
- 注册接收
BroadcastReceiver br = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
this.registerReceiver(br, filter);
- 要停止接收广播
unregisterReceiver(br)
- 注意动态注册的需要在对应的方法中解除注册
两种注册方法的区别
- 动态注册的接收器必须要在程序启动之后才能接收到广播;
- 静态注册的接收器即便程序未启动也能接收到广播,比如想接收到手机开机完成后系统发出的广播就只能用静态注册了。
广播的发送
- 标准广播(异步)
//通过sendBroadcast发送标准合家欢广播
Intent intent = new Intent("com.example.songsong.MY_BROADCAST");
sendBroadcast(intent);
- 有序广播(同步)
- 定义:发送出去的广播被广播接收者按照先后顺序接收
- 接收广播的顺序规则(同时面向静态和动态注册的广播接受者)
- 按照Priority属性值从大-小排序;
- Priority属性相同者,动态注册的广播优先;
特点:
- 接收广播按顺序接收;
- 先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;
- 先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播
//通过sendOrderBroadcast发送
Intent intent = new Intent("com.example.songsong.MY_BROADCAST");
sendOrderBroadcast(intent,null);
/*给广播接收器设置优先级 */
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.LOCAL_BROADCAST" />
</intent-filter>
//广播接收器截断:
public void onReceive(Context context, Intent intent) {
abortBroadcast();
}
- 本地广播
//发送1:实例化localBroadcastManager
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
//发送2:发送广播
Intent intent = new Intent("android.net.conn.CONNECTIVITY_CHANGE");
localBroadcastManager.sendBroadcast(intent);
//接收1:实例化IntentFilter和接收器LocalReceiver
IntentFilter intentFilter = new IntentFilter();
LocalReceiver localReceiver = new LocalReceiver();
//接收2:设置广播接收类型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//接收3:进行动态注册本地广播
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
//接收4:在onDestroy中取消注册
localBroadcastManager.unregisterReceiver(localReceiver);
//接收5:在localReceiver中继承BroadcastReceiver并重写onReceiver。
对进程状态的影响
BroadcastReceiver 的状态(无论它是否在运行)会影响其所在进程的状态,而其所在进程的状态又会影响它被系统终结的可能性。例如,当进程执行接收器(即当前在运行其 onReceive() 方法中的代码)时,它被认为是前台进程。除非遇到极大的内存压力,否则系统会保持该进程运行。
但是,一旦从 onReceive() 返回代码,BroadcastReceiver 就不再活跃。接收器的宿主进程变得与在其中运行的其他应用组件一样重要。如果该进程仅托管清单声明的接收器(这对于用户从未与之互动或最近没有与之互动的应用很常见),则从 onReceive() 返回时,系统会将其进程视为低优先级进程,并可能会将其终止,以便将资源提供给其他更重要的进程使用。
- 以 API 级别 26 或更高级别为目标的应用无法再在其清单中注册用于隐式广播的广播接收器,除了一些特殊的广播外:官方文档