前言
Google从Android8.0版本开始,对在清单文件中静态注册广播做了限制。
特殊广播(动态注册广播接收者)
说:有序广播和无序广播之前,咱们先来说下Android中一些特殊的广播如何接收呢?
- 特殊的广播:指那些操作比较频繁的广播事件类型。如:屏幕的开、关广播,电量的变化广播等等
- 这种特殊的广播事件在 AndroidManifest.xml 中注册是无效的!
因为这种特殊的广播如果在清单文件中注册,会浪费内存资源。你可以想象下,如果有100个应用在清单文件中注册了手机电量变化广播接收者,那当手机电量发生变化时,这100个应用的广播接收者就有可能都运行...那会造成什么结果...。所以:只能动态注册(在代码中注册)
如何动态注册广播呢
- 定义一个广播接收者(两种方式)
//方式一:动态注册一个广播接受者
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
Log.e("动态注册广播接收者", "屏幕 关闭 了");
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
Log.e("动态注册广播接收者", "屏幕 开启 了");
}
}
};
//方式二:单独定义一个 广播接收者
public class TestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获取发送的广播
String body = intent.getStringExtra("body");
Log.e("广播接收者", "body:" + body);
}
}
- 动态注册广播接收者(注册定义好的广播接收者)
//注册:接收系统广播 的 广播接收者
//创建一个意图过滤器
IntentFilter filter = new IntentFilter();
//为意图过滤器添加广播事件类型
filter.addAction(Intent.ACTION_SCREEN_OFF);//关屏广播
filter.addAction(Intent.ACTION_SCREEN_ON);//开屏广播
//注册广播
this.registerReceiver(receiver, filter);
// 注册:自定义的广播接收者(action的添加有以下两种方式)
//方式一:构造器传参
IntentFilter filter = new IntentFilter("wo-shi-yi-ge-action");
//方式二:使用addAction()方法添加
// IntentFilter filter = new IntentFilter();
// filter.addAction("wo.ye.shi.yi.ge.action");
//filter.addCategory("");
//filter.addDataType("");
//filter.addDataScheme("");
this.registerReceiver(receiver2, filter);
- 发送一个广播(切记:广播发送之前要先注册广播接收者,否则接收者是接收不到消息的)。针对于自定义的广播事件。
切记发送和接收的 action 要保持一致,不然是收不到消息的
//注册成功之后,发送一个广播
Intent intent = new Intent();
intent.setAction("wo-shi-yi-ge-action");
//intent.setAction("wo.ye.shi.yi.ge.action");
intent.putExtra("body", "我是数据");
this.sendBroadcast(intent);
无序广播
- 类似于新闻联播,不关心是否有人接收,都会发送。
- 不可以中止。
- 特殊广播:也是一种无序广播。
- 广播接收者的两种注册方式:静态注册 和 动态注册。动态注册上面已经叙述过了。下面咱们说说:静态注册(分:安卓8.0之前和安卓8.0之后)
- 先在清单文件(AndroidManifest.xml)中,静态注册
<!--在配置文件中:静态注册一个广播接收者-->
<receiver android:name=".receiver.TestDemoReceiver">
<!--定义一个意图过滤器来接收(监听)指定的action-->
<intent-filter>
<!--可以配置系统的固定的时间类型。如:开关机广播、拨打电话广播等等-->
<!--<action android:name="android.intent.action.ACTION_CLOSE_SYSTEM_DIALOGS" />-->
<!--也可以配置自定义的 action(事件类型)-->
<action android:name="x.xx.xxx.无序" />
</intent-filter>
</receiver>
- 发送一个无序广播(Android版本8.0之前 )
Intent intent = new Intent();//获取 Intent 对象
//使用隐式意图,为intent添加指定的广播事件类型
intent.setAction("x.xx.xxx.无序");
intent.putExtra("body", "我是数据");//封装数据
this.sendBroadcast(intent);//发送广播
- 发送一个无序广播(Android版本8.0之后 ,必须使用全类名方式)
Intent intent = new Intent();
intent.setAction("x.xx.xxx.无序");
//该方式适用:给其他应用的广播接收者发送消息(指定应用的包名、指定类的全类名)
//intent.setComponent(new ComponentName("包名", "包名.receiver.TestReceiver"));
//intent.setClassName("包名", "包名.receiver.TestReceiver");
//如果是给自身应用内广播接收者发送广播
//intent.setComponent(new ComponentName(this, TestReceiver.class));
intent.setClassName(this, "包名.receiver.TestReceiver");
intent.putExtra("body", "我是数据");
this.sendBroadcast(intent);
有序广播
- 类似于*下发的红头文件,一级一级向下发送,中间如果接收失败,发送就会终止。
- 发送过程中,可以终止。终止后,后续的接收者则无法接收(有一种特殊情况)。
定义 4 个 广播接收者:模拟有序广播的接收
//广播接收者:有序广播-1
public class Test1Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String resultData = getResultData();
//有序广播里终止广播
//abortBroadcast();
setResultData("国家发放补贴800");
Toast.makeText(context, "省接收:"+resultData, Toast.LENGTH_SHORT).show();
}
}
//广播接收者:有序广播-2
public class Test2Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String resultData = getResultData();
setResultData("国家发放补贴600");
Toast.makeText(context, "市接收:"+resultData, Toast.LENGTH_SHORT).show();
}
}
//广播接收者:有序广播-3
public class Test3Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String resultData = getResultData();
Toast.makeText(context, "县接收:"+resultData, Toast.LENGTH_SHORT).show();
}
}
特殊的广播接收者:广播接收者(看成:监察者,用于模拟上述说的有序广播即便被中断,依然可以接收到广播消息的特例)
//广播接收者:有序广播 最终接收者
public class Test0Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String resultData = getResultData();
Toast.makeText(context, "最终数据:"+resultData, Toast.LENGTH_SHORT).show();
}
}
- 有序广播接收
Android版本8.0之前(不包含android8.0版本),只需要在清单文件中静态配置就可以。
- 在配置文件中(AndroidManifest.xml),如果没有设置优先级(android:priority="XXX"),那么接收到广播的先后顺序会根据配置文件中书写的顺序产生变化,接收顺序会由上而下。这种接收顺序不可取,所以,为了避免这种情况,有序广播的接收者必须配置优先级,防止接收顺序错乱。
- priority 的优先级:最高1000 —— 最低 -1000
静态注册代码如下:
<receiver android:name=".receiver.Test1Receiver">
<intent-filter android:priority="1000">
<action android:name="x.xx.xxx.有序" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.Test2Receiver">
<intent-filter android:priority="999">
<action android:name="x.xx.xxx.有序" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.Test3Receiver">
<intent-filter android:priority="998">
<action android:name="x.xx.xxx.有序" />
</intent-filter>
</receiver>
从Android版本8.0开始,由于Google对清单文件中静态注册广播接收者做了限制,只能通过动态注册的方式,实现有序广播。
动态注册代码如下:
IntentFilter filter2 = new IntentFilter();
filter2.addAction("x.xx.xxx.有序");
filter2.setPriority(999);
this.registerReceiver(new Test2Receiver(), filter2);
IntentFilter filter1 = new IntentFilter();
filter1.addAction("x.xx.xxx.有序");
filter1.setPriority(1000);
this.registerReceiver(new Test1Receiver(), filter1);
IntentFilter filter3 = new IntentFilter();
filter3.addAction("x.xx.xxx.有序");
filter3.setPriority(998);
this.registerReceiver(new Test3Receiver(), filter3);
发送一个有序广播
Test0Receiver:是定义的一个特殊的广播接收者,在发送有序广播的时候以参数的形式传递进去
- 若在有序广播传递过程中,假如:A 中止了广播的传递。Test0Receiver 依然会接收到数据。接收到的是: A 发送的数据(如果 A 没有发送数据,那么Test0Receiver接收到的数据就和 A 接收到的数据相同)。
- 若在有序广播传递过程中,假如:广播的传递没有被中止, C作为最后一个接收对象。如果 C没有继续发送数据,那么Test0Receiver 接收到的数据 和 C 接收到的数据一样。如果C有继续发送数据,那么Test0Receiver 接收到的数据就是C发送的数据
Intent intent = new Intent();
intent.setAction("x.xx.xxx.有序");
//发送一个有序广播
//sendOrderedBroadcast(Intent intent, //发送广播的意图对象(可以携带数据)
// String receiverPermission, //接收权限(如果为空,则不需要权限)
// BroadcastReceiver resultReceiver, //广播接收者对象(自己创建的最终的广播接收者,可以无须在清单文件中配置,也会接收到广播 )
// Handler scheduler, //若传null,则默认是在主线程中
// int initialCode, //初始化的一个值。可默认:Activity.RESULT_OK
// String initialData, //可发送的初始化数据(相当于一条广播数据)。可为null
// Bundle initialExtras) //可绑定数据传递(Intent对象也可以,所以可为null)
this.sendOrderedBroadcast(intent, null, new Test0Receiver(), null, Activity.RESULT_OK, "国家发放补贴1000", null);
Android的有序广播和无序广播(解决安卓8.0版本之后有序广播的接收问题)的更多相关文章
-
解决 Electron 5.0 版本出现 require is not defined 的问题
Electron已经发布了5.0正式版,升级后发现原来能运行的代码报错提示require is not defined 经查相关资料,原来官方在5.0版本修改了nodeIntegration的默认值, ...
-
解决cocos2d-X 2.0版本后创建的Android项目提示org.cocos2dx.lib.Cocos2dxActivity找不到问题
原地址: http://blog.163.com/zhoulong19880518@126/blog/static/6070970220132511558143/ 解决方法: 复制 ***\co ...
-
彻底解决安卓7.0及以上版本抓包https失败
目录 现象 原因 解决办法 webview抓包失败 警告 现象 android7.0以上的手机https抓包失败(安装了https证书也不行) 原因 android7.0+的版本新增了证书验证(系统证 ...
-
[异常解决] 安卓6.0权限问题导致老蓝牙程序出现异常解决办法:Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission...
一.问题: 之前写的一款安卓4.4的应用程序,用来连接蓝牙BLE,而现在拿出来用新的AS编译(此时SDK为6.0,手机也是6.0)应用程序并不能搜索到蓝牙,查看log总是报权限错误: Need ACC ...
-
如何解决安卓(系统版本低) CSS3 动画问题---高性能动画
目前对提升移动端CSS3动画体验的主要方法有几点: 尽可能多的利用硬件能力,如使用3D变形来开启GPU加速 -webkit-transform: translate3d(0, 0, 0); -moz- ...
-
vue单页面项目中解决安卓4.4版本不兼容的问题
1.cnpm安装 cnpm i babel-polyfill --save cnpm i es6-promise --save 2.main.js引入 import ‘babel-polyfill‘ ...
-
国产计算框架Mindspore1.3.0 gpu源代码中的cmake文件存在问题(bug),openmpi的url错误,导致不能正常编译——成功解决mindspore-gpu-1.3.0版本不能从源代码中编译的问题
mindspore 的 r1.3 分支 在gpu方式编译下存在问题,无法编译,具体编译结果参考: https://www.cnblogs.com/devilmaycry812839668/p/1505 ...
-
Android(java)学习笔记179:BroadcastReceiver之 有序广播和无序广播(BroadcastReceiver优先级)
之前我们在Android(java)学习笔记178中自定义的广播是无序广播,下面我们要了解一下有序广播: 1. 我们首先了解一下有序广播和无序广播区别和联系? (1) 有序广播> 接受者 ...
-
Android(java)学习笔记122:BroadcastReceiver之 有序广播和无序广播(BroadcastReceiver优先级)
之前我们在Android(java)学习笔记178中自定义的广播是无序广播,下面我们要了解一下有序广播: 1. 我们首先了解一下有序广播和无序广播区别和联系? (1)有序广播> 接受者有优先级, ...
随机推荐
-
C++模板类继承的一个小技巧
先说一下background前段时间想实现一个Sqlite localstorage的功能,对应不同的Model 实体有不同的table, 每一次sql操作的函数签名中会有model实体中的struc ...
-
我 Git 命令列表 (1)【转】
转自:http://www.microsofttranslator.com/bv.aspx?from=en&to=zh-CHS&a=http%3A%2F%2Fvincenttam.gi ...
-
检测URL地址是否有响应
今天突然出来了一个问题,URL地址调用导致程序卡死(原因是服务挂了,磁盘坏了) 然后想到了,再调用URL地址前先判断下地址是否有响应,这样不就可以解决问题了吗? C# 代码: /// <summ ...
-
ZOJ 3817	Chinese Knot
题意:给定4个长度为N的字符串( N <= 100000),然后构成一个“中国结”,给定目标串,问能否从某个节点出发走一遍得到目标串,其中不能连续通过3个中心节点,也就是从字符串一个端点转移到其 ...
-
苹果 App 转移图文详解
目前公司在做App转移操作,在网上搜索相关资料加上自己的亲自操作,整理成一个文档,希望能给你提供帮助. 如转载请添加出处. 此文章只是为了记录一个Apple ID下的APP,转移到另外一个Apple ...
-
HTML表单元素
HTML表单元素 表单元素同意的形式向用户(例:文本字段,下拉列表,单箱,检查盒等)输入元素信息 表单标签 文本域(Text Fields) 当用户要在表单中键入字母,数字等内容时,就会用到文本域 单 ...
-
关于STM32 IAP
转眼间天亮了...... 然后就想起了一个朋友QQ的个性签名:年轻人总是要为一些自己认为有意义的事情而废寝忘食,通宵达旦,直至白发方休........ 对了这篇文章一定会介绍的很详细,请细嚼慢咽... ...
-
IOS学习5——属性与成员变量
[转]iOS中属性与成员变量的区别 ios中属性修饰符的作用 1. 属性用property声明 2. 简而言之,对于目前的ios开发,属性和成员变量的区别,完全可以不管. 3. 这个是历史原因造成的. ...
-
jquery tmpl生成导航
引入<script src="jquery.tmpl.min.js"></script> html<ul class="nav" ...
-
bootstrap基础学习小记(二)排版、列表、代码风格、表格
排版——标题.副标题.段落(正文文本).强调内容.粗体.斜体.强调相关的类.文本对齐 <!DOCTYPE HTML> <html> <head> <meta ...