Android开发——BroadcastReceiver知识总结

0.  前言

BroadcastReceiver作为Android四大组件之一,像一个全局的监听器一样,是用来监听系统或者应用发出的广播信息,再在其onReceive()中执行相应的逻辑处理。

如可以监听系统的开机广播、电量较少的广播,也可以用来实现自己应用中不同组件之间的通信,如数据库中CURD后发送一个广播,并传递少量的数据,使某个Service中的变量发生改变。当然如果数据的发送量比较大就不建议使用广播接收者来接收了,因为BroadcastReceiver接收数据的开销还是比较大的。转载请注明出处为SEU_Calvin的博客

1.  BroadcastReceive的三种类型

1.1  普通广播

普通广播是完全异步的,而不是有所谓的接收顺序,消息传递的效率也比较高,并且无法中断广播的传播。

Intent intent = new Intent();
intent.setAction("com.seu.calvin.mybroadcastreceiver");
intent.putExtra("data", "hello");
sendBroadcast(intent);

1.2  有序广播

有序广播有所谓的优先级(谷歌文档上表示最大优先级为1000,但是实际上最大的级数是int最大值2147483647),优先级决定了接收顺序,在onReceiver()方法执行时,广播不会传播到下一个接收者,当前的广播接收者可以中断广播的传播,也可以将intent中的数据进行修改。

//发送有序广播
sendOrderedBroadcast(intent, null);

//接收有序广播
public void onReceive(Context arg0, Intent intent) {
//参数为true表示前一个广播没有结果时创建新的Bundle;false表示不创建新的Bundle
Bundle bundle = getResultExtras(true);
bundle.putString("data", "hello again");
  setResultExtras(bundle);
  //终止广播传给下一个广播接收者
  //abortBroadcast();
}

1.3  粘性广播

粘性广播已经被废弃,我们可以通过sendStickyBroadcast()来发送粘性广播。

当粘性广播发送后会滞留在操作系统中,如果有新的符合匹配规则的广播接收者动态注册了(在广播发送之后动态注册),也将会收到这个广播消息。而对于静态注册,效果等同于普通广播。

2.  BroadcastReceive动静态注册的区别

1BroadcastReceiverManifest中静态注册后,应用一经安装,该广播接收者就常驻在系统中了(该广播接收者和应用可以认为已经脱离关系了),无论应用是否处于运行状态都可以接收对应的广播事件

动态注册的广播接收者由registerReceiver开始监听,由unregisterReceiver撤销监听,如果应用退出时没有撤销监听,应用将会报错。显然应用退出后,将不再接收对应的广播事件。

 (2)如果广播接收者是静态注册的,通过intent启动一个activity/service时,若无法匹配不会报错,反之动态注册的话会报错

 (3)如果动静态注册使用的优先级都一样,那么动态注册的广播接收者优先级更高。

3.  BroadcastReceive机制

3.1  广播接收者注册

3.1.1  静态注册

静态广播由PackageManagerService负责,当手机启动或者新安装了应用的时候,PackageManagerService会扫描手机中所有已安装的APP应用,AndroidManifest.xml中有关注册广播的信息解析出来,存储至一个全局静态变量当中。

PackageManagerService扫描目录的顺序如下:system/frameworksystem/app  vendor/appdata/appdrm/app-private,当处于同一目录下时按照file.list()的返回顺序。

因此当然是可以通过PackageManager取消静态注册的,取消后再次启动应用,静态注册就会失效。

 

3.1.2 动态注册

动态广播由ActivityManagerService负责,当代码执行到动态注册广播时进行加载(Binder通信),最后会存储在一个另外的全局静态变量中。

 

3.2  广播发送

广播发送时会通过Binder机制,分别和PackageManagerService以及ActivityManagerService进行广播的发送。后者再查找出符合匹配条件的广播接收者。

 

然后就是广播顺序,如果是普通广播

1)动态广播接收器优先于静态广播接收器;

2)同优先级的静态广播接收器:先扫描到的大于后扫描到的;

3)同优先级的动态广播接收器:先注册的大于后注册的。   

 

如果是有序广播,会将动态广播处理器和静态广播处理器合并在一起处理广播,顺序如下:

1)优先级高的先接收;

2)同优先级,动态优先于静态;

3)同优先级的静态广播接收器:先扫描到的大于后扫描到的;

4)同优先级的动态广播接收器:先注册的大于后注册的。

 

3.3  广播接收者的处理

广播接收者拿到广播后产生一个广播接收者的实例并回调BroadcastReceiver中的onReceive()方法

特别需要注意的是这个实例的生命周期只有10秒,如果10秒内没执行结束onReceiver(),系统将会报错。另外在onReceiver()执行完后,该实例将会被销毁,所以如果要处理耗时任务,不要在onReceiver()中直接创建子线程,而是通过intent调用service处理业务

4.  拓展

静态注册的广播接收器即使app已经退出,依然可以接收到广播的说法,自Android 3.1开始有可能不再成立

因为Android 3.1开始系统在Intent与广播相关的flag中增加了两个参数,分别是:

intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);//包含已经停止的包
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);//不包含已经停止的包

即自Android3.1开始,系统广播自带FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。详情参考Android官方文档

可以考虑使用将Service与App本身设置成不同的进程来在已退出app里接收广播。而自定义广播,自行为Intent添加flag参数即可。

转载请注明出处为:Android开发——BroadcastReceiver知识总结_SEU_Calvin的博客-CSDN博客

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用BroadcastReceiver实时监听电量的Android源码: 1. 在AndroidManifest.xml文件中添加以下权限和广播接收器: ```xml <uses-permission android:name="android.permission.BATTERY_CHANGED" /> <receiver android:name=".BatteryReceiver"> <intent-filter> <action android:name="android.intent.action.BATTERY_CHANGED" /> </intent-filter> </receiver> ``` 2. 创建BatteryReceiver类实现BroadcastReceiver接口,重写onReceive()方法: ```java public class BatteryReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); float batteryLevel = level / (float) scale; Log.d("BatteryLevel", batteryLevel * 100 + "%"); } } ``` 3. 在MainActivity中注册广播接收器: ```java public class MainActivity extends AppCompatActivity { private BatteryReceiver batteryReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 注册广播接收器 batteryReceiver = new BatteryReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); registerReceiver(batteryReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); // 取消注册广播接收器 unregisterReceiver(batteryReceiver); } } ``` 这样就可以实时监听电量了。当电量发生变化时,会在Logcat中输出当前电量百分比。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值