日更 16 天
本文主要记录以下三个知识点:
Android 中的 BroadcastReceiver 是什么?
BroadcastReceiver 的分类
BroadcastReceiver 的使用
Android 中的 BroadcastReceiver
BroadcastReceiver
又叫 广播,顾名思义它的作用就是用来发送通知,在Android 中可以理解为发送消息。在 Android 中广播分为 标准广播、有序广播
标准广播
它是一种完全异步执行的广播,在广播发出之后,如果没有被中断,那么所有的广播消费者就会接收到这条广播,而且是没有顺序的接收到。由于它的无序状态,所以这种广播是无法被中断的,类似下图:
![](https://img.haomeiwen.com/i1942372/746ee7253e5d9c2f.png)
有序广播
它是一种同步执行的广播。广播生产者发出广播之后,在同一个时刻只会有一个广播消费者接收到这条广播。这个广播是有优先级顺序的,优先级高的会优先收到消息,在消息处理完了之后才传递给下一个广播消费者。由于它是有顺序的发送,所以可以在某个优先级高的消费者接收到消息后就不传递给下一个消费者,这就控制了广播的中断。
![](https://img.haomeiwen.com/i1942372/4fafab74e9a77bf1.png)
广播的使用
在 Android 系统中内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机会发送一条广播,系统电脑发生变化会发出一条广播,时间和时区发生改变也会发出一条广播。当然系统内置的广播不可能满足我们的需求,所以我们还可以自定义广播。如果想要接收到这些广播,那么就需要广播接收器来接受信息。
- 系统广播
- 自定义广播
- 标准广播
- 有序广播
系统广播-动态注册监听网络变化
这里讲到了广播的注册方式,广播的注册方式分为 动态和静态注册两种。
动态注册是指在代码中根据页面是否要接受消息来动态注册广播(记得有注册就有注销~)。
静态注册是指在AndroidManifest.xml
文件中直接注册。
两种注册方式的区别:
-
静态注册的方式可以保证在应用程序安装之后,
BroadcastReceiver
会一直存在,通常用于监听系统状态的改变,比如说手机的电量,wifi
状态,等等。 -
动态注册顾名思义相对静态注册要灵活的多,这样注册的
BroadcastReceiver
通常用于更新UI
的状态。在页面关闭时可关闭广播,或者在不需要接受广播的时候关闭(注意内存泄露)。
动态注册实现网络状态监听的代码如下:
public class AActivity extends AppCompatActivity {
private NetworkChangeReceiver mNetworkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
// 动态注册网络监听广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
mNetworkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(mNetworkChangeReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 动态注销网络监听广播
unregisterReceiver(mNetworkChangeReceiver);
}
// 这里比较简单就做内部类写了,真实情况最好还是单独做一个类来维护
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager service = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (service != null){
// 需要在 androidmanifest.xml 中添加权限 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
NetworkInfo activeNetworkInfo = service.getActiveNetworkInfo();
if (activeNetworkInfo != null && activeNetworkInfo.isAvailable()){
Toast.makeText(context, "有网", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context, "无网", Toast.LENGTH_SHORT).show();
}
}
}
}
}
再来一个系统广播的使用例子,静态注册实现开机启动
- 定义一个广播接收者
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "开机启动完成", Toast.LENGTH_SHORT).show();
}
}
- 在
AndroidManifest.xml
中注册广播,同时添加上监听开机启动广播需要的权限。
// 监听开机启动需要的权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
// 静态注册广播
<receiver android:name=".launch_model.BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
以上是两个系统广播的静态注册和动态注册使用例子,上面的使用都不难,唯一找不到方向的是这几个权限去哪找?Android 官网应该有介绍,我就没去找了,下面给出几个 常见的系统广播对应的权限和action
几个 常见的系统广播对应的权限和action
常见的系统广播
- 系统启动完成
- 网络状态
- 电量变化
- 监听SD卡状态
- 监听应用的安装、卸载、更新
常见的 Action 常量
在
<intent-filter></intent-filter>
中定义个action
,这里的 action 是广播的唯一标识,系统的广播能够发给所有监听了这个广播消息的软件监听者,这也验证了广播是 跨进程的一种通信方式。
-
ACTION_TIME_CHANGED
:系统时间被改变。 -
ACTION_DATE_CHANGED
:系统日期被改变。 -
ACTION_TIMEZONE_CHANGED
:系统时区被改变。 -
ACTION_BOOT_COMPLETED
:系统启动完成。 -
ACTION_PACKAGE_ADDED
:系统添加包。 -
ACTION_PACKAGE_CHANGED
:系统的包改变。 -
ACTION_PACKAGE_REMOVED
:系统的包被删除。 -
ACTION_PACKAGE_RESTARTED
:系统的包被重启。 -
ACTION_PACKAGE_DATA_CLEARED
:系统的包数据被清空。 -
ACTION_BATTERY_CHANGED
:电池电量改变。 -
ACTION_BATTERY_LOW
:电池电量低。 -
ACTION_POWER_CONNECTED
:系统连接电源。 -
ACTION_POWER_DISCONNECTED
:系统与电源断开。 -
ACTION_SHUTDOWN
:系统被关闭。
自定义广播---标准广播
主要是用于刷新
UI
,在自定义广播中,可以发送标准广播和有序广播。标准广播是高效的,但是是不可被打断的,无序的。有序广播是可以被打断,有序的。
实现方式同上面介绍的监听开机启动,唯一不同的是 action
是我们自定义的 action
,完整代码如下
// 定义一个广播
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "自定义广播", Toast.LENGTH_SHORT).show();
}
}
// 静态注册广播
<receiver android:name=".launch_model.MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<!--这里的 action 一般以类名的具体路径命名-->
<action android:name="com.dong.test1.launch_model.MyBroadcastReceiver"/>
</intent-filter>
</receiver>
// 点击按钮发送广播
Button btnSendBroad = findViewById(R.id.btn_send_broad);
btnSendBroad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 广播的 action
Intent intent = new Intent("com.dong.test1.launch_model.MyBroadcastReceiver");
// 这里的 intent 可以携带一些数据 使用 intent.putXXX() 方法传递
sendBroadcast(intent);
}
});
自定义广播---有序广播
前面介绍的广播都是无序的,那么如何实现广播的有序发送和接受呢?也很简单,只需要两步即可
- 给所有要监听该广播的action 设置为一样的值。
- 在
<intent-filter android:priority="100">
中添加priority='值'
值越大优先级越高。
<receiver android:name=".launch_model.MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<!--这里的 action 一般以类名的具体路径命名-->
<action android:name="com.dong.test1.launch_model.MyBroadcastReceiver"/>
</intent-filter>
</receiver>
这时候如果在接受器中接受到消息不想往下传递,可以使用
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "自定义广播", Toast.LENGTH_SHORT).show();
// 中断广播消息,在广播优先级低于这条广播接收者之后的的广播都收不到消息。
abortBroadcast();
}
}
自定义广播---本地广播
上面介绍的广播都属于全局广播,也就是别人只要知道我们的 action
就可以给我们的广播一直发送消息,这是不太安全的,所以 Android 引入了本地广播机制。它主要是通过 LocalBroadcastManager
来对广播进行管理。实现的简单例子如下:
// 本地广播接收者
class LocalReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "本地广播", Toast.LENGTH_SHORT).show();
}
}
private LocalReceiver mLocalReceiver;
private LocalBroadcastManager mLocalBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
// 获取到本地广播管理者实例
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
Button btnSendBroad = findViewById(R.id.btn_send_broad);
btnSendBroad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.dong.test1.launch_model.MyBroadcastReceiver");
// 通过本地广播管理来发送广播
mLocalBroadcastManager.sendBroadcast(intent);
}
});
IntentFilter intentFilter = new IntentFilter();
mLocalReceiver = new LocalReceiver();
// 通过本地广播管理来注册广播mLocalBroadcastManager.registerReceiver(mLocalReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 通过本地广播管理来注销广播
mLocalBroadcastManager. unregisterReceiver(mLocalReceiver);
}
本地广播的使用和动态注册广播的使用是类似的,只是这里多了一个LocalBroadcastManager
管理类,它的注册、注销以及广播的发送都是通过管理类的对象去操作。
本文完~
网友评论