BroadcastReceiver基础使用
BroadCastReceiver简介
BroadCastReceiver,即广播接收器,运行在主线程用于监听全局广播
作为Android四大组件之一,BroadCastReceiver起着重要的作用,一般用于接收推送,跨进程通信等不方便直接通信操作的地方或者监听某些不定时完成的事务
广播主要有两种:有序广播和无序广播
- 无序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,并且是没有先后顺序,效率搞,但是接收者不能传递也不能截断广播
- 有序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,但是会按照广播接收者的优先级来决定接收的先后顺序,每一个接收者都有权修改并将修改的广播传给下一个接收者,也可以拦截。
BroadcastReceiver的实现原理
之前使用的时候并没有在意它的实现原理,只是知道这么用
广播的设计模式是标准的观察者模式,对于广播而言最重要的是Android的AMS(ActivityManagerService),消息发布者在AMS中注册,通过Binder机制发送广播,AMS在注册列表寻找到合适的接收者,将广播发送到接收者的消息循环队列(BroadcastQueue)中,广播接收者通过消息循环拿到广播并调用回调方法onReceive();
这观察者模式好屌,吓得我赶紧去看这个设计模式怎么用了
定义一个BroadcastReceiver
定义个广播接收器还是挺简单的
- 首先我们要新建一个类(至于是单独文件的类还是内部类这个要看使用场景,不过都可以的)并继承BroadcastReceiver类
- 重写里面的onReceive方法
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//接收广播后的操作
}
}
BroadcastReceiver的注册
作为Android四大组件之一,你Activity和Service都在Manifest里面注册了,我BroadcastReceiver要是不注册,我不要面子哒?
BroadcastReceiver的注册分为两种:静态注册和动态注册
静态注册
静态注册实在AndroidManifest里面添加
<receiver>
标签
<receiver
//是否能够实例化这个接收器可以为true,若为false则不能被实例化
android:enabled=["true" | "false"]
//此接收器能否接受其他APP发出的广播,如果内部包含intent-filter标签则默认为true,否则默认false
android:exported=["true" | "false"]
//一个代表广播接收器的图标,不定义默认为application标签的icon
android:icon="drawable resource"
android:label="string resource"//标签
//这个属性一般为广播接收器实现类的类名(全名,要有包名的那种;或者直接.CLASSNAME,这样系统会默认吧manifest的包名加到前面)
android:name="string"
//这个属性用于定义把消息发送给该广播接收器的广播器所必须要有的权限。
android:permission="string"
这个属性用于设置该广播接收器应该运行在那个进程中的进程名。
android:process="string">
<intent-filter>
//这里的action,就是我们发送的广播的事件名
<action android:name="actionName" />
</intent-filter>
</receiver>
当此app首次启动时,系统会自动实例化该广播接收器的实现类,并注册到系统中。
动态注册
是指不在Manifest里面添加标签,而是在代码中动态调用Context的registerReceiver()方法。
private MyBroadcastReceiver mBroadcastReceiver;
@Override
protected void onResume(){
super.onResume();
mBroadcastReceiver = new MyBroadcastReceiver ();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
registerReceiver(mBroadcastReceiver, intentFilter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mBroadcastReceiver);
}
动态广播由于需要注销防止内存泄漏,所以推荐在onResume方法中注册,onPause方法中注销,同时重复注册,重复注销也不允许
在onResume()注册、onPause()注销是因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露。
静态注册与动态注册的区别
- 两个方式的注册方式不同
- 静态:在manifest中注册
- 动态:在代码中注册
- 两个方式的监听范围不同
- 静态:会时刻监听广播
- 动态:在特定时刻监听广播
- 两个方式的生命周期不同
- 静态:常驻后台,不受任何组件生命周期影响,耗电多占内存大
- 动态:部常驻,灵活,跟随组件的生命周期变化,一旦移除就不会接受广播
发送广播
广播是通过sendBroadcast()方法,以Intent为传输工具进行发送的
广播主要分为5类:
- 普通广播
- 系统广播
- 有序广播
- 粘性广播
- 应用内广播
普通广播
Intent intent = new Intent();
intent.setAction(NROMAL_ACTION);
sendBroadcast(intent);
NROMAL_ACTION 就是你之前注册的广播事件
系统广播
这个并不是手动发送的,而是系统默认发送的,我们只需要监听就好
具体操作 | action名称 |
---|---|
监听网络变化 | android.net.conn.CONNECTIVITY_CHANGE |
关闭或打开飞行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
充电时或电量发生变化 | Intent.ACTION_BATTERY_CHANGED |
电池电量低 | Intent.ACTION_BATTERY_LOW |
电池电量充足(即从电量低变化到饱满时会发出广播 | Intent.ACTION_BATTERY_OKAY |
系统启动完成后(仅广播一次) | Intent.ACTION_BOOT_COMPLETED |
按下照相时的拍照按键(硬件按键)时 | Intent.ACTION_CAMERA_BUTTON |
屏幕锁屏 | Intent.ACTION_CLOSE_SYSTEM_DIALOGS |
设备当前设置被改变时(界面语言、设备方向等) | Intent.ACTION_CONFIGURATION_CHANGED |
插入耳机时 | Intent.ACTION_HEADSET_PLUG |
未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡) | Intent.ACTION_MEDIA_BAD_REMOVAL |
插入外部储存装置(如SD卡) | tent.ACTION_MEDIA_CHECKING |
成功安装APK | Intent.ACTION_PACKAGE_REMOVED |
成功删除APK | Intent.ACTION_BATTERY_CHANGED |
重启设备 | Intent.ACTION_REBOOT |
屏幕被关闭 | Intent.ACTION_SCREEN_OFF |
屏幕被打开 | Intent.ACTION_SCREEN_ON |
关闭系统时 | Intent.ACTION_SHUTDOWN |
重启设备 | Intent.ACTION_REBOOT |
当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播
有序广播
发送出去的广播被广播接收者按照先后顺序接收,这里的有序是针对接受者的
- 广播接收的顺序规则
- 按照Priority属性的值,从大到小排序
- Priority属性的值相同时,动态注册的广播优先
使用方式
sendOrderedBroadcast(intent);
应用内广播
- 注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;
- 发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中,通过intent.setPackage(packageName)指定报名
在广播发送和接收时,增设相应权限permission,用于权限验证;
除了以上几种方式,也可以使用LocalBroadcastManager
使用方式上与全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将参数的context变成了LocalBroadcastManager的单一实例,对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册
//注册应用内广播接收器
//步骤1:实例化BroadcastReceiver子类 & IntentFilter
MyBroadcastReceiver mBroadcastReceiver = new MyBroadcastReceiver ();
IntentFilter intentFilter = new IntentFilter();
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//步骤3:设置接收广播的类型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
//发送应用内广播
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);
关于onReceive(Context context,Intent intent)方法
对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的
- 对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
- 对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
- 对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context。
- 对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;