广播介绍
Android 应用可以通过 Android 系统和其他 Android应用发送或接收广播消息,类似于发布-订阅设计模式。这些广播会在所关注的事件发生时发送。例如,Android系统会在发生各种系统事件时发送广播,例如系统启动或设备开始充电时。应用还可以发送自定义广播,例如,通知其他应用它们可能感兴趣的内容(例如,一些新数据已下载)。
为了保持最佳系统运行状况,系统会优化广播的传送。因此,广播的传送时间无法保证。需要低延迟进程间通信的应用应考虑绑定服务。
广播作为Android四大组件之一,不但是系统发送重要消息或者是内部组件之间的通信,被广泛的运用于各种任务和场景。广播主要有系统广播和自定义广播,自定义广播主要用标准广播、顺序广播和粘性广播。
标准广播
标准广播(Normal Broadcast)是Android中一种常见的广播类型。它是一种异步广播,意味着发送广播后,发送者不会等待接收者的处理结果,而是立即返回。所有匹配该广播的接收者都会同时接收到广播消息。
sendBroadcast(intent, null);
有序广播
有序广播(Ordered Broadcast)是Android中另一种常见的广播类型。与标准广播不同,有序广播是按照优先级顺序依次发送给匹配的接收者,并且每个接收者在处理广播后可以选择终止广播或将广播传递给下一个接收者。
// 发送有序广播
sendOrderedBroadcast(intent, null);
粘性广播
粘性广播(Sticky Broadcast)是Android中一种特殊类型的广播。与标准广播和有序广播不同,粘性广播会保留在系统中,即使没有匹配的接收者。当有新的接收者注册时,它们会立即收到最新的粘性广播。
/ 发送粘性广播
sendStickyBroadcast(intent);
发送广播
Intent intent = new Intent();
intent.setComponent(new ComponentName(“com.example.addtask”, MessageReceiver.class.getName()));
intent.setAction("com.example.MY_MESSGE_ACTION");
intent.putExtra("messageType", 1);
sendBroadcast(intent);
接收广播
静态注册
在清单文件配置广播接收器
<receiver
android:name=".MessageReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="997">
<action android:name="com.example.MY_MESSGE_ACTION" />
</intent-filter>
</receiver>
exported属性表示是否允许接收本程序以外的广播
enabled属性表示是否启用这个广播接收器
public class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("MessageReceiver", "BroadcastReceiver: Action: " + intent.getAction());
// an Intent broadcast.
if(context == null || intent == null) {
return;
}
// 处理业务逻辑
}
}
动态注册
动态注册,仅在页面运行时生效
public class FragmentBestTryActivity extends BaseActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver; //自己写的接收器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_best_try);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); //添加要监听的内容
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter); //注册监听,一定在onDestroy中取消注册
}
//注册广播
class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); //关于网络连接的管理器
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isAvailable()){
Toast.makeText(FragmentBestTryActivity.this, "连接", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(FragmentBestTryActivity.this, "断开", Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver); //一定要取消注册
}
}
广播Android 8.0 适配
Android8.0 以上限制隐式广播,静态广播无法接收
隐式广播是一种不针对应用内特定组件的广播,因此它不会传送到以 Android 8.0 或更高版本为目标平台的应用中已在清单注册的接收器。
intent.setComponent(new ComponentName("包名", "包名+ 类名如MessageReceiver"));//完整路径
在Android 7.0及以下版本不是必须的,但是Android 8.0或者更高版本,发送广播的条件更加严苛,必须添加这一行内容。创建的ComponentName实例化对象有两个参数,第1个参数是指接收广播类的包名,第2个参数是指接收广播类的完整类名。
Android14 延迟广播
应用处于缓存状态时,系统会延迟不太重要的系统广播(如ACTION_SCREEN_ON)。一旦应用从缓存状态进入活跃进程生命周期,系统就会传递所有延迟的广播。
ps: 隐式Intent
如需接收隐式 intent,您必须在 intent 过滤器中添加 CATEGORY_DEFAULT类别。否则目标activity无法收到intent。建议使用显示Intent,防止intent乱飞和减少资源消耗。若不对其他应用开放,应将exported 属性设置为 “false”。
声明接收隐式intent类型
<category android:name="android.intent.category.DEFAULT"/>
Android12 强制声明exproted
如果应用中的 activity、服务或广播接收器使用 intent 过滤器,并且未明确设置 android:exported
的值,则您的应用无法安装在搭载 Android 12 或更高版本的设备上。
系统广播
系统广播是由Android操作系统自身发出的广播,用于通知应用程序有关设备状态和系统事件的变化。
常见的系统广播:网络状态变化、设备电量变化、开机广播、屏幕开启关闭广播等。
系统开机广播
- 声明注册信息
<receiver android:name=".server.BootReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
- 声明系统权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
注意事项
- 如果许多应用在其清单中注册接收同一广播,可能会导致系统启动大量应用,从而对设备性能和用户体验产生重大影响。为避免这种情况,请优先使用上下文注册而非清单声明。
- 请勿使用隐式 intent 广播敏感信息。任何注册接收广播的应用都可以读取这些信息。使用显示Intent或增加限制(增加包名)等。
- 由于接收器的 onReceive(Context, Intent) 方法在主线程上运行,因此它应该快速执行并返回。尽量不要在此方法中处理耗时操作或启动后台服务