Broadcast
广播主要分为两种类型:标准广播和有序广播。
- 标准广播(Normal broadcasts):一种异步执行的广播,所有广播接收器都可以接收,无法被截断。
- 有序广播(Ordered broadcasts):一种同步执行的广播,同一时刻只有一个广播接收器能够接收,当前广播接收器的逻辑执行完后该广播继续传递,但可以被截断不再传递。存在先后顺序,优先级高的广播接收器可以先接收该广播。
Broadcast Receiver
广播接收器可以对相应广播进行注册,以进行接收并处理。注册方式分为动态注册(在代码中注册)和静态注册(在 AndroidManifest.xml 清单文件中注册)。
动态注册接收广播
安卓系统内置了很多系统级别的广播,以网络变化为例实现动态注册监听。
-
访问网络状态需要在 AndroidManifest 中声明
android.permission.ACCESS_NETWORK_STATE
权限,注意并不是网络权限。<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
自定义一个继承自 BroadcastReceiver 的广播接收器类 NetworkChangeReceiver,重写
onReceiver()
方法。接收到相应广播后会自动执行该方法。public class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 使用 getSystemService() 获取系统连接管理器 ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // 使用连接管理器获取网络信息 NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); // 当网络信息为空或网络不可用时,弹出 Toast 提示 if (networkInfo == null || ! networkInfo.isAvailable()) { Toast.makeText(context, "network is unavailable.", Toast.LENGTH_SHORT).show; } } }
-
在 Activity 中创建 IntentFilter 对象,并添加目标广播的 Action。
public class MainActivity extends AppCompatActivity { private IntentFilter intentFilter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); } }
-
在 Activity 中创建自定义广播接收器对象,并将该对象和 IntentFilter 对象传入
registerReceiver()
方法中,实现动态注册。public class MainActivity extends AppCompatActivity { private IntentFilter intentFilter; private NetworkChangeReceiver networkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); networkChangeReceiver = new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver, intentFilter); } }
-
重写 Activity 的
onDestroy()
方法,在里面使用unregisterReceiver()
方法取消注册。动态注册的广播接收器一定要取消注册。public class MainActivity extends AppCompatActivity { @Override protected void onDestroy() { super.onDestroy(); if (networkChangeReceiver != null) { unregisterReceiver(networkChangeReceiver); // 将广播接收器置空,方便回收 networkChangeReceiver = null; } } }
静态注册接收广播
动态注册的广播接收器可以自由控制注册和注销,比较灵活,但必须要在程序启动后才能接收广播。想要不启动程序就能接收广播就需要使用静态注册了。安卓 8.0 开始谷歌取消了大部分静态广播的注册,仅保留了部分可静态注册的广播。以开机完成为例。
-
自定义一个继承自 BroadcastReceiver 的广播接收器类 BootCompletedReceiver,重写
onReceiver()
方法。接收到相应广播后会自动执行该方法。public class BootCompletedReceiverextends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete.", Toast.LENGTH_SHORT).show; } }
-
在 AndroidManifest.xml 中的
<application>
标签下添加<receiver>
标签及内容。步骤 1 和 2 可以使用 Android Studio 提供的快捷方式完成,在对应包上右键 -> New -> Other -> Broadcast Receiver,然后输入类名和勾选相应选项即可创建。<application ... > <!-- enabled 代表是否启用该广播接收器 --> <!-- exported 代表是否运行该广播接收器接收本程序以为的广播 --> <receiver android:name=".BootCompletedReceiver" android:enabled="true" android:exported="true"> </receiver> </application>
-
在该广播接收器的
<receiver>
标签下添加<intent-filter>
标签,并在其中添加目标广播的 Action。<application ... > <receiver android:name=".BootCompletedReceiver" android:enabled="true" android:exported="true"> <!-- 在 <intent-filter> 中添加目标广播的 Action --> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> </application>
-
监听系统开机广播也是需要声明权限的,在清单文件中添加
android.permission.RECEIVE_BOOT_COMPLETED
权限。<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
发送标准广播
发送标准广播非常简单,在需要发送广播的地方创建一个带 Action 的 Intent,将其传入并调用 sendBroadcast()
方法即可发送一条标准广播。
Intent intent = new Intent("DIY_BROADCAST");
sendBroadcast(intent);
发送有序广播
其实发送有序广播和发送标准广播区别不大,使用起来只是将发送广播的方法改为 sendOrderedBroadcast()
,另外需要传入的参数多了一个所需权限字符串,可以传入 null
。如果权限字符串不为空则代表该广播需要拥有对应权限的广播接收器才可以接收。
Intent intent = new Intent("DIY_BROADCAST");
sendOrderedBroadcast(intent, null);
前面说到有序广播是有先后顺序的,存在优先级,也可以截断,这两个设置其实也很简单。优先级可以通过 IntentFilter 的 setPriority()
方法设置,或者在清单文件下对应广播接收器的 <intent-filter>
标签中添加 android:priority=""
属性。截断广播则更只需要在对应广播接收器的 onReceiver()
方法中调用 abortBroadcast()
方法即可。
使用本地广播
前面使用的广播都是系统全局广播,可以被其他任何应用程序接收到,同时也能接收到其他应用发来的广播,这是很不安全的。那么使用只能在自己应用程序内部传递的本地广播就很有必要。
本地广播的用法并不复杂,主要是使用 LocalBroadcastManager 来对广播进行管理,同时它也提供了发送和注册广播接收器的方法。以点击按钮发送本地广播并接收为例。
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private ButtonClickReceiver buttonClickReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button_diy_broadcast);
intentFilter = new IntentFilter();
intentFilter.addAction("DIY_BROADCAST");
buttonClickReceiver = new ButtonClickReceiver();
// 获取本地广播管理器实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
// 通过本地广播管理器注册
localBroadcastManager.registerReceiver(buttonClickReceiver, intentFilter);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("DIY_BROADCAST");
// 通过本地广播管理器发送自定义广播
localBroadcastManager.sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (buttonClickReceiver != null) {
// 通过本地广播管理器注销
localBroadcastManager.unregisterReceiver(buttonClickReceiver);
buttonClickReceiver = null;
}
}
private class ButtonClickReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Button is clicked.", Toast.LENGTH_SHORT).show;
}
}
}