Android查缺补漏--BroadcastReceiver的类型与使用
Broadcast 是一种被用于应用内和应用之间传递信息的机制。一个广播可以对应多个接受者。一个完整的广播机制,需要具有以下三个要素:
- 发送广播的Broadcast
- 接受广播的BroadcastReceiver
- 传递信息的Intent
广播的注册分为静态注册和动态注册:
- 静态注册:静态注册的广播是指在AndroidManifest中注册的广播,此种广播在应用安装时就被系统解析,不需要启动应用就可以收到相应的广播。
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
- 动态注册:通过Context.registerReceiver()来实现,不需要时要通过Context.unRegisterReceiver()解除广播,此种广播必须应用启动后才能注册并接收广播。
// 动态注册广播接收器
registerReceiver(new DynamicBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
广播又分为普通广播、有序广播、本地广播和sticky广播。
一、普通广播
普通广播通过Context.sendBroadcast()发送,我们没有办法制定Receiver们对于普通广播的接收顺序。理论上所有的接收器(Receiver)接收到广播的顺序不确定,但一般是按照其在AndroidMainfest.xml文件中注册的顺序(不绝对)。
普通广播中,接受者不能将处理结果传递给下一个接收器,也无法终止广播的传播。
如下代码是一个静态注册的广播示例:
public class MyBroadcastReceiver extends BroadcastReceiver {
String TAG = MyBroadcastReceiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
}
}
然后再AndroidMainfest.xml中注册这个广播:
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
接下来在Activity中调用Context.sendBroadcast()发送广播就可以了:
Intent intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一个普通广播");
sendBroadcast(intent);
log如下:
12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个普通广播
- 普通广播的接收顺序测试
我们仿照MyBroadcastReciver创建多个接收器,代码一样:
/**
* 静态注册的广播接收器2
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast2Receiver extends BroadcastReceiver {
String TAG = MyBroadcast2Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
}
}
/**
* 静态注册的广播接收器3
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast3Receiver extends BroadcastReceiver {...}
/**
* 静态注册的广播接收器4
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast4Receiver extends BroadcastReceiver {...}
/**
* 静态注册的广播接收器5
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast5Receiver extends BroadcastReceiver {...}
/**
* 静态注册的广播接收器6
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast6Receiver extends BroadcastReceiver {...}
然后在AndroidMainfest.xml中为以上广播都注册同一个action
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast6Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast2Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast3Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast4Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast5Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
点击发送广播,查看log:
12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.268 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.271 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.273 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.277 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.280 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个普通广播
二、有序广播
在AndroidMainfest.xml中注册广播时通过priority(值越优先级越高)节点为广播添加优先级,然后再用Context.sendOrderedBroadcast()发送,接收者们就会按照优先级顺序依次执行。
有序广播的接收者和给下一个接收者传递数据,并且接收者在收到广播之后可以抛弃广播,使广播不再向后传递。
为上面6个接收器添加优先级:
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter android:priority="1">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast6Receiver">
<intent-filter android:priority="6">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast2Receiver">
<intent-filter android:priority="2">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast3Receiver">
<intent-filter android:priority="3">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast4Receiver">
<intent-filter android:priority="4">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast5Receiver">
<intent-filter android:priority="5">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
然后通过sendOrderedBroadcast发送广播观察log:
intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一个有序广播");
sendOrderedBroadcast(intent, null);
log如下:
12-08 18:17:26.455 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.462 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.464 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.465 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.466 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.467 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个有序广播
- abortBroadcast()抛弃广播:
普通的广播是没有办法抛弃的,否则会抛出RuntimeException的异常。
只有有序广播才可以通过此方法抛弃。我们在MyBroadcast6Receiver中添加abortBroadcast()方法:
public class MyBroadcast6Receiver extends BroadcastReceiver {
String TAG = MyBroadcast6Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
abortBroadcast();
Log.i(TAG, "丢弃广播");
}
}
然后点击发送有序广播,log如下:
12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 丢弃广播
可以看到广播已经被丢弃了。
- setResult()传递给下一个接收者结果。
- getResult()接收上一个接收者的结果。
在MyBroadcast6Receiver中添加setResult方法,在MyBroadcast5Receiver添加getResult方法:
public class MyBroadcast6Receiver extends BroadcastReceiver {
String TAG = MyBroadcast6Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
// abortBroadcast();
// Log.i(TAG, "丢弃广播");
setResult(006, "我是老6传来的消息", null);
}
}
public class MyBroadcast5Receiver extends BroadcastReceiver {
String TAG = MyBroadcast5Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
String data = getResultData();
Log.i(TAG, "data=" + data);
}
}
log如下:
12-08 18:40:01.415 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: data=我是老6传来的消息
12-08 18:40:01.440 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.442 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.445 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.447 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个有序广播
三、本地广播
以上的广播对于系统来说是全局的,发出广播后,系统内的应用只要注册了相应的接收器就都可以收到广播。如果我们想在本应用发出的广播只在此应用内可以收到,那么可以使用本地广播了。
本地广播由 LocalBroadcastManager 管理,是在 API 21 以后添加的,使用起来也很方便,需要先通过 LocalBroadcastManager.getInstance() 方法获取其单例,剩下的用法与其他广播类似,其主要方法有以下几个:
- registerReceiver():注册广播接收器。
- unregisterReceiver():解除广播接收器。
- sendBroadcast():发送异步广播。
- sendBroadcastSync():发送同步广播。
使用本地广播时,无需在AndroidMainfest.xml中注册,必须使用 LocalBroadcastManager.getInstance(...).registerReceiver(..)来注册接收器。
我们来写个本地广播的小栗子,首先注册两个本地广播:
LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcast2Receiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
然后发送本地广播:
intent.putExtra(INTENT_INFO, "我是一个本地广播");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
log如下:
12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个本地广播
12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个本地广播
四、sticky广播(不建议使用)
sticky广播会一直处于滞留状态,sticky广播被发出后,只要有能够匹配其的新接收器被注册了就可以收到广播,sticky广播通过Context.sendStickyBroadcast()发送。
最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!
参考文献:
- 《Android开发艺术探索》
- 《Android开发进阶从小工到专家》
Android查缺补漏--BroadcastReceiver的类型与使用的更多相关文章
- Android查缺补漏(View篇)--事件分发机制源码分析
在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)-- ...
- Android查缺补漏(IPC篇)-- 进程间通讯基础知识热身
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8479282.html 在Android中进程间通信是比较难的一部分,同时又非常 ...
- Android查缺补漏(IPC篇)-- Bundle、文件共享、ContentProvider、Messenger四种进程间通讯介绍
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8387752.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 款进程通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(View篇)--自定义 View 的基本流程
View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...
- Android查缺补漏(IPC篇)-- 进程间通讯之Socket简介及示例
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8425736.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(线程篇)-- IntentService的源码浅析
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8975114.html 在Android中有两个比较容易弄混的概念,Servic ...
- Android查缺补漏--Activity生命周期和启动模式
一.生命周期 onCreate():启动Activity时,首次创建Activity时回调. onRestart():再次启动Activity时回调. onStart():首次启动Activity时在 ...
随机推荐
- 全排列Permutations
描述 Given a collection of numbers, return all possible permutations.For example,[1,2,3] have the foll ...
- Get started with Google Analytics
What is Google Analytics Google Analytics is a Google official analytics tool that is primarily used ...
- MyEclipse10激活方法
背景:因为以前一直使用的是myeclipse8.6版本,但因为版本太低有些功能不支持,于是想试用下myeclipse10.0版本,但是下载后发现需要激活,但在激活的过程中遇到了很多坑,于是便有了本文的 ...
- 浅谈Verilog HDL代码编写风格
消失了好久,没有写文章,也没有做笔记,因为最近再赶一个比赛,时间很紧,昨天周六终于结束了,所以趁着周末这会儿有时间,写点东西,记录下来.首先我学习FPGA才一年多,我知道自己没有资格谈论一些比较深层次 ...
- 在64位Win7环境+64位JDK下,运行64位Eclipse,提示“Failed to load the JNI shared library”错误,提示jvm.dll不对
-startup plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar --launcher.library plugins/org.ecl ...
- WebView之js调用Android类的方法传递数据
1,具体的思路如下: 在android中写一个Activity,里面写一个webview,这个webview加载本地的一个html文件,显示这个网页,这个网页包括一个用户名和密码的输入框和两个按钮(只 ...
- 隐藏17年的Office远程代码执行漏洞(CVE-2017-11882)
Preface 这几天关于Office的一个远程代码执行漏洞很流行,昨天也有朋友发了相关信息,于是想复现一下看看,复现过程也比较简单,主要是简单记录下. 利用脚本Github传送地址 ,后面的参考链接 ...
- django之第二天
今天学习目标: 一,路由系统 1,默认处理函数 2,动态URL 3,分级匹配 4,反射实现动态路由 二.中间件 三.Model(重点) 1,创建表 2,操作表数据 四.Form (重点) 1,用户提交 ...
- python 批量修改数字类的文件名
今天碰到一个小问题,下载音频的时候,文件名的名字变成了数字,排序呢,是按照数字的大小往下排的. 想自己给它们重新起名字,但是又不打乱音频的顺序.好吧,那就自己写写代码吧. 思路就是遍历音频文件的数字文 ...
- 利用反射机制设计Dao
本文主要介绍如何通过Java反射机制设计通用Dao,针对中间使用到的方法进行介绍,不对反射做全面的介绍. 测试方法大家可以直接拷贝去试一下,特地写成比较通用的,注意参数就好了,当然最后还是会附上完整的 ...