ACTION_BOOT_COMPLETED:系统启动完成。
ACTION_PACKAGE_ADDED:系统添加包。
ACTION_PACKAGE_REMOVED:系统的包被删除。
ACTION_PACKAGE_DATA_CLEARED:系统的包数据被清空。
ACTION_BATTERY_CHANGED:电池电量改变。
ACTION_BATTERY_LOW:电池电量低。
ACTION_TIME_CHANGED:系统时间被改变。
ACTION_DATE_CHANGED:系统日期被改变。
ACTION_TIMEZONE_CHANGED:系统时区被改变。
上面这些Action是什么?这些就是 系统广播。
前言:广播是什么?
广播有系统广播和应用广播
系统广播
系统自己在很多时候都会发送广播,比如上面列出上面列出的系统启动完成、系统添加包、电池电量低等,系统都会发送广播,这台手机上的每个APP都会收到,当然由于现在Android隐私安全越来越严格,所以有些广播接收还受到严格的权限控制。
应用广播
应用自定义一些广播,可以用于进程间通信。 例如:应用程序可以发送广播来传递数据给其他应用,或者通知其他应用你完成了什么事。
广播接收者(BroadcastReceiver) Android四大组件之一,通信的一种手段,广播接收者用于接收来自其他应用程序或者系统的广播消息。
这篇文章主要是讲解自定义广播的使用。
一.两种注册方式:动态&静态
1.动态注册
注册:
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.dynamic");
//注册广播接收
registerReceiver(new DynamicReceiver(), filter);
解绑:
unregisterReceiver(new DynamicReceiver());
发送广播:
//动态广播
Intent intent = new Intent();
intent.setAction("com.example.dynamic");
intent.putExtra("value", "你好!");
sendBroadcast(intent);
继承BroadcastReceiver 的 DynamicReceiver 类:
public class DynamicReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "动态广播:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
Log.d(getClass().getSimpleName() + "-TEST", "动态广播");
}
}
2.静态注册
清单文件配置:
<receiver android:name=".broadcast.StaticReceiver">
<intent-filter>
<action android:name="com.example.static" />
</intent-filter>
</receiver>
发送广播:
//静态广播
Intent intent = new Intent("com.example.static");
intent.putExtra("value", "你好!");
//应用内广播,解决android 8.0 无法接受静态注册广播问题。
intent.setClassName(MainActivity.this, "com.example.myfirstproject.broadcast.StaticReceiver");
sendBroadcast(intent);
继承BroadcastReceiver 的 StaticReceiver 类:
public class StaticReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "静态广播:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
Log.d(getClass().getSimpleName(), "静态广播");
}
}
注意:如果你的安卓版本是8.0+,静态注册需要加下面这段代码才能在你应用内的Receiver接收到静态注册广播。
intent.setClassName(MainActivity.this, "com.example.myfirstproject.broadcast.StaticReceiver");
如果你需要向其他应用中静态注册的广播接收者发送广播,加上下面代码试试:
//该方式适用:给其他应用的广播接收者发送消息(指定应用的包名、指定类的全类名)
intent.setComponent(new ComponentName("包名", "包名.XXXReceiver"));
官方说明:Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-declared receivers. If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically).
意思就是说:从android 8.0(API 26)开始,对清单文件中静态注册广播接收者增加了限制,建议大家不要在清单文件中静态注册广播接收者。
二.普通广播&有序广播
为了验证下普通广播和有序广播的区别,需要在增加一个动态广播接收者Dynamic2Receiver。代码同上面动态注册的DynamicReceiver一样。
public class Dynamic2Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "动态广播2:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
Log.d(getClass().getSimpleName() + "-TEST", "动态广播2");
//拦截广播
//abortBroadcast();
}
}
接下来动态注册两个接收者Receiver,增加优先级setPriority,注意区别两个接收者的优先级:Dynamic2Receiver是1000优先级高于DynamicReceiver-1000,也就是Dynamic2Receiver要优先于DynamicReceiver接收到广播。
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.dynamic");
//注册广播接收
filter.setPriority(-1000);
registerReceiver(new DynamicReceiver(), filter);
//注册广播接收
filter.setPriority(1000);
registerReceiver(new Dynamic2Receiver(), filter);
//本地广播
localBroadcastManager = LocalBroadcastManager.getInstance(this);
filter.addAction("com.example.local");
localBroadcastManager.registerReceiver(new LocalReceiver(), filter);
同样有注册就要有解绑:
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(new DynamicReceiver());
unregisterReceiver(new Dynamic2Receiver());
}
接下来看下不同的广播发送方式的区别。
1.普通广播
Intent intent = new Intent();
intent.setAction("com.example.dynamic");
intent.putExtra("value", "你好!");
sendBroadcast(intent);
标准广播的发送方式,接受者是异步执行。
输出Log:
2021-08-06 13:24:09.396 11531-11531/com.example.myfirstproject D/Dynamic2Receiver-TEST: 动态广播2
2021-08-06 13:24:09.424 11531-11531/com.example.myfirstproject D/DynamicReceiver-TEST: 动态广播
1.有序广播
Intent intent = new Intent();
intent.setAction("com.example.dynamic");
intent.putExtra("value", "你好!");
sendOrderedBroadcast(intent, null);
输出Log:
2021-08-06 13:26:21.591 12332-12332/com.example.myfirstproject D/Dynamic2Receiver-TEST: 动态广播2
2021-08-06 13:26:21.756 12332-12332/com.example.myfirstproject D/DynamicReceiver-TEST: 动态广播
使用sendOrderedBroadcast发送有序广播。接收者是按优先级高到低进行执行。 并且我们可以在优先级高的接收者Dynamic2Receiver对广播进行拦截,这样DynamicReceiver就不会执行了。
对广播进行拦截使用如下代码:
//拦截广播
abortBroadcast();
加上拦截代码输出:
2021-08-06 13:25:35.709 12085-12085/com.example.myfirstproject D/Dynamic2Receiver-TEST: 动态广播2
突发奇想,在普通广播加上abortBroadcast();会有什么反应呢?
结果是程序不会崩溃但是LogCat里有错误log:
BroadcastReceiver trying to return result during a non-ordered broadcast
三.本地广播
已经有了全局广播为什么还要增加一个本地广播呢?
这是因为BroadcastReceiver的设计初衷是全局性,可接收来自本应用和其他应用发过来的intent广播。这也同时给app带来了一定的安全风险。为了解决这个问题,Android增加了本地广播LocalBroadcastManager。
LocalBroadcastManager 只会将广播限定在当前应用程序中。LocalBroadcastManager 发送的广播不会离开你的应用程序,同样也不会接收来自其它应用程序的广播,因此你可以放心的在 LocalBroadcastManager 中传播敏感信息,而不会被其他应用截取。同时由于LocalBroadcastManager不需要用到跨进程机制,因此相对 BroadcastReceiver 而言要更为高效。LocalBroadcastManager只在动态广播时使用,静态广播不能使用LocalBroadcastManager。
所以如果你没有跟其他应用通信的需求的广播优先使用LocalBroadcastManager。
熟悉了上面动态注册发送接受广播,本地广播就很简单了。
本地广播都是通过LocalBroadcastManager来进行调用管理的。
private LocalBroadcastManager localBroadcastManager;
注册本地广播:
IntentFilter filter = new IntentFilter();
//本地广播
localBroadcastManager = LocalBroadcastManager.getInstance(this);
filter.addAction("com.example.local");
localBroadcastManager.registerReceiver(new LocalReceiver(), filter);
解绑本地广播:
localBroadcastManager.unregisterReceiver(new LocalReceiver());
调用本地广播:
Intent intent = new Intent();
intent.setAction("com.example.local");
intent.putExtra("value", "你好!");
localBroadcastManager.sendBroadcast(intent);
定义一个接收者Receiver:
public class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "本地广播:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
Log.d(getClass().getSimpleName() + "-TEST", "本地广播");
}
}
以上,其实跟动态注册大部分代码重合。只需要在注册,解绑,发送广播中通过LocalBroadcastManager来管理就可以了。
输出Log:
2021-08-06 13:28:37.218 12332-12332/com.example.myfirstproject D/LocalReceiver-TEST: 本地广播
结语
以上就是关于广播的一些介绍了。如果你还感兴趣系统广播的使用方式,可以再看看我的这篇文章,# Android开机自启动的两种方式,里面对系统开机广播作了介绍:
传送门: # Android开机自启动的两种方式