接收广播BroadcastReceiver
Broadcast Receiver用于接收并处理广播通知(broadcast announcements)。多数的广播是系统发起的,如地域变换、电量不足、来电来信等。程序也可以播放一个广播。程序可以有任意数量的 broadcast receivers来响应它觉得重要的通知。broadcast receiver可以通过多种方式通知用户:启动activity、使用NotificationManager、开启背景灯、振动设备、播放声音等,最 典型的是在状态栏显示一个图标,这样用户就可以点它打开看通知内容。
通常我们的某个应用或系统本身在某些事件(电池电量不足、来电来短信)来临时会广播一个Intent出去,我们可以利用注册一个Broadcast Receiver来监听到这些Intent并获取Intent中的数据。
一个Broadcast receiver只有一个简单的回调函数:
onReceive(Context curContext, Intent
broadcastMsg),当一个广播消息被Receiver监听到时,Android会调用它的onReceive()方法,并将包含消息的
Intent对象传给它。
onReceive中代码的执行时间不要超过5s,否则android会弹出超时dialog。
此时是否另开一个线程来处理耗时的操作呢?
Receiver只在onReceive方法执行时是激活状态,只要onReceive一返回,Receiver就不再是激活状态了。Receiver进
程是被一个激活状态的broadcast
receiver所保护而不被系统终止的,一旦onReceive返回,Receiver进程broadcast
receiver所保护而变为一个空进程,空进程是可以在任意时刻被终止的。这就带来了一个问题:当响应一个广播信息的处理十分耗时的时候,那么就应该把
这个处理放在一个单独的线程里去执行,来保证主线程里的其他用户交互组件能够继续运行,而一旦这么做,当onReceive()唤起一个线程后就会马上返
回,这时就会把Receiver进程放到被终止的境地。解决这个问题的方案是在onReceive()里开始一个Service,让这个Service去
做这件事情,那么系统就会认为这个进程里还有活动正在进行。
我们看一个简单的demo,该demo实现了一个自定义broadcast。
- public class BroadcastTest extends Activity {
- public static final String NEW_LIFEFROM_DETECTED = “com.android.broadcasttest.NEW_LIFEFROM”;
- public void onCreate(Bundle savedInstanceState) {
- Button btn0 = (Button)findViewById(R.id.btn0);
- btn0.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- Intent it = new Intent(NEW_LIFEFROM_DETECTED);
- sendBroadcast(it);
- }
- });
- }
- }
接收端在onReceive()中实现了当接收到broadcast所做的动作。
- Public class MyBroadcastReceiver extends BroadcastReceiver {
- // TODO
- Public void onReceive(Context context, Intene intent){
- ......
- }
- }
在receiver的action中定义了该receiver能够接受的广播,Manifest.xml定义部分:
- <receiver android:name=”.MyBroadcastReceiver”>
- <intent-filter>
- <action android:name=”com.android.broadcasttest.NEW_LIFEFROM” /> </intent-filter>
- </receiver>
Receiver。这种模式适合于这样的场景:某事件发生 -> 通知Broadcast ->
启动相关处理应用。比如,监听来电、邮件、短信之类的,都隶属于这种模式。
OnPause等事件中通过unregisterReceiver反注册,通过这种方式使其能够在运行期间保持对相关事件的关注。比如,一款优秀的词典软
件,可能会有在运行期间关注网络状况变化的需求,使其可以在有廉价网络的时候优先使用网络查询词汇,在其他情况下,首先通过本地词库来查词。而这样的监
听,只需要在其工作状态下保持就好,不运行的时候,管你是天大的网路变化,与我何干。其模式可以归结为:启动应用 -> 监听事件 ->
发生时进行处理。
册的BroadcastReceiver被触发。对于同样是动态注册的BroadcastReceiver,优先级别高的将先被触发,而静态注册的
BroadcastReceiver总是按照静态注册的顺序执行。
- <receiver android:name="Receiver1">
- <intent-filter>
- <!-- 和Intent中的action对应 -->
- <action android:name="com.forrest.action.mybroadcast"/>
- </intent-filter>
在代码中注册
- IntentFilter filter = new IntentFilter("com.forrest.action.mybroadcast"); // 和广播中Intent的action对应
- MyBroadcastReceiver br = new MyBroadcastReceiver();
- registerReceiver(new MyBroadcastReceiver(), filter);
- //注销
- unregisterReceiver(br);
- public class Receiver1 extends BroadcastReceiver {
- private Context context;
- public static final int NOTIFICATION_ID = 10001;
- public void onReceive(Context context, Intent intent) {
- this.context = context;
- showNotification();
- }
- private void showNotification() {
- Notification notification = new Notification(R.drawable.icon, "来电话啦...", System.currentTimeMillis());
- PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);
- notification.setLatestEventInfo(context, "来电话啦...嘿嘿", "赶紧接电话,否则误大事了", contentIntent);
- NotificationManager notificationManager = (NotificationManager) context.getSystemService(
- android.content.Context.NOTIFICATION_SERVICE);
- notificationManager.notify(NOTIFICATION_ID, notification);
- }
- }
- public class Receiver2 extends BroadcastReceiver {
- private Context context;
- @Override
- public void onReceive(Context context, Intent intent) {
- this.context = context;
- deleteNotification();
- }
- private void deleteNotification() {
- NotificationManager notificationManager = (NotificationManager) context.getSystemService(android.content.Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(Receiver1.NOTIFICATION_ID);
- }
- }
- public class MainActivity extends Activity {
- private final String ACTION_SEND = "com.forrest.action.SENDMESSAGE",
- ACTION_CLEAR = "com.forrest.action.CLEARNOTIFICATION";
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- ( (Button) findViewById(R.id.btn1) ).setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- clickMenuItem(ACTION_SEND);
- }
- });
- ( (Button) findViewById(R.id.btn2) ).setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- clickMenuItem(ACTION_CLEAR);
- }
- });
- }
- private void clickMenuItem(final String action) {
- Intent intent = new Intent(action);
- sendBroadcast(intent);
- }
- }
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:name=".MainActivity"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <receiver android:name="Receiver1">
- <intent-filter>
- <action android:name="com.forrest.action.SENDMESSAGE"/>
- </intent-filter>
- </receiver>
- <receiver android:name="Receiver2">
- <intent-filter>
- <action android:name="com.forrest.action.CLEARNOTIFICATION"/>
- </intent-filter>
- </receiver>
- </application>
android.provider.Telephony.SMS_RECEIVED动作的Intent。注意,这个动作是一个字符串值,SDK
1.0不再包含对这个字符串的引用,因此,在你的应用程序中,你需要显式的指定它。
对于应用程序监听SMS Intent广播,首先需要添加RECEIVE_SMS权限。通过在应用程序manifest中添加一个uses-permission,如下面的片段所示:
<uses-permission android:name=”android.permission.RECEIVE_SMS”/>
SMS广播Intent包含了新来SMS的细节。为了提取包装在SMS广播Intent的Bundle中的SmsMessage对象数组,使用pdus
key来提取SMS
pdus数组,其中,每个对象表示一个SMS消息。将每个pdu字节数组转化成SmsMessage对象,调用
SmsMessage.createFromPdu,传入每个字节数组,如下面的片段所示:
- Bundle bundle = intent.getExtras();
- if (bundle != null) {
- Object[] pdus = (Object[]) bundle.get(“pdus”);
- SmsMessage[] messages = new SmsMessage[pdus.length];
- for (int i = 0; i < pdus.length; i++)
- messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
- }
每个SmsMessage对象包含SMS 消息的细节,包括源地址(手机号),时间和消息体。
下面的例子演示了一个Broadcast Receiver实现了onReceive函数来检查新来的短信是否以@echo字符串开始,如果是,发送相同的文本给那个手机:
- public class IncomingSMSReceiver extends BroadcastReceiver
- {
- private static final String queryString = “@echo “;
- private static final String SMS_RECEIVED = “android.provider.Telephony.SMS_RECEIVED”;
- public void onReceive(Context _context, Intent _intent){
- if (_intent.getAction().equals(SMS_RECEIVED)){
- SmsManager sms = SmsManager.getDefault();
- Bundle bundle = _intent.getExtras();
- if (bundle != null){
- Object[] pdus = (Object[]) bundle.get(“pdus”);
- SmsMessage[] messages = new SmsMessage[pdus.length];
- for (int i = 0; i < pdus.length; i++)
- messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
- for (SmsMessage message : messages){
- String msg = message.getMessageBody();
- String to = message.getOriginatingAddress();
- if (msg.toLowerCase().startsWith(queryString)){
- String out = msg.substring(queryString.length());
- sms.sendTextMessage(to, null, out, null, null);
- }
- }
- }
- }
- }
- }
为了监听短信,使用Intent Filter来注册Broadcast Receiver,使其监听android.provider.Telephony.SMS_RECEIVED动作,如下面的片段所示:
- final String SMS_RECEIVED = “android.provider.Telephony.SMS_RECEIVED”;
- IntentFilter filter = new IntentFilter(SMS_RECEIVED);
- BroadcastReceiver receiver = new IncomingSMSReceiver();
- registerReceiver(receiver, filter);
在Android中,Broadcast是一种广泛运用在应用程序之间异步传输信息的机制。Android系统通过发出广播消息,来通知各应用组件一些系
统事件,如地域变换、电量不足、来电信息等,这些消息通常称为系统消息。第三方应用也可以广播消息,这些消息称为自定义消息。
广播消息在本质上就是一个Intent对象。
BroadcastReceiver用于接收并处理广播消息。不管是系统消息还是自定义消息,都可以通过BroadcastReceiver来进行处理。形象的比喻,Intent是一种一对一的通信,广播消息是一种一对多的通信。
b、 广播消息的处理流程
对于广播消息的处理,大致要经过消息发送、BroadcastReceiver注册和消息处理三个环节。
c、消息发送
广播消息的实质就是一个Intent对象。使用sendBroadcast
()或sendStickyBroadcast()方法发出去的Intent,所有满足条件的BroadcastReceiver都会随机地执行其onReceive()方法;
sendOrderBroadcast
()发出去的Intent,会根据BroadcastReceiver注册时Intent Filter 设置的优先级的顺序来执行,相同优先级的BroadcastReceiver则是随机执行。
sendStickyBroadcast
()方法主要的不同的是,Intent在发送后一直存在,并且在以后调用registerReceiver注册相匹配的BroadcastReceiver时会把这个Intent直接返回。
d、注册BroadcastReceiver
注册BroadcastReceiver有两种方式:
一种方式是,静态地在AndroidManifest.xml中用<receiver>标签声明,并在标签内用<intent-filter>标签设置过滤器
另一种方式是,动态在代码中先定义并设置好一个Intent Filter
对象,然后再需要注册的地方调用Context.registerReceiver(BroadcastReceiver,intentFilter)方
法,如果取消时就调用Context.unregisterReceiver(BroadcastReceiver)方法。如果用动态注册
BroadcastReceiver的Context对象被销毁时,BroadcastReceiver也就自动取消注册了。
根据Activity组件的生命周期,通常在onResume中注册BroadcastReceiver,在onPause中取消BroadcastReceiver。
e、处理消息
当广播消息发送以后,所有已经注册的BroadcastReceiver会检查注册时的Intent
Filter是否与发送的Intent相匹配,若匹配则就会调用BroadcastReceiver的onReceive()方法。另外,若在使用
sendBroadcast()的方法是指定了接收权限,则只有在AndroidManifest.xml中用标记<uses-
permission>声明了拥有此权限的BroadcastReceiver才会有可能接收到发送来的Broadcast。
一个BroadcastReceiver可以处理多个广播消息,具体做法为在onReceive()方法调用Intent参数的getAction判断传进来的动作,即可进行不同的处理。
f、处理系统广播消息
在广播消息中,有一类特殊的广播消息,它们特殊在只能由Android系统发出,这类广播消息称为系统广播。
ACTION_TIME_TICK 系统时间已经改变。该事件每分钟被广播一次,只能通过动态注册BroadcastReceiver来响应。
ACTION_TIME_CHANGED 系统时间被设置
ACTION_TIMEZONE_CHANGED 系统时区被改变
ACTION_BOOT_COMPLETED 系统启动完成
ACTION_PACKAGE_ADDED 新的应用程序被安装
ACTION_PACKAGE_CHANGED 应用程序被改变
ACTION_PACKAGE_REMOVED 应用程序被卸载
ACTION_PACKAGE_RESTARTED 应用程序被重新启动
ACTION_PACKAGE_DATA_CLEARED 应用程序数据被清空
ACTION_UID_REMOVED 用户ID被删除
ACTION_BATTERY_CHANGED 点量信息改变
ACTION_POWER_CONNECTED 外接电源被连通
ACTION_POWER_DISCONNECTED 外接电源被断开
ACTION_SHUTDOWN 系统关闭
静态注册BroadcastReceiver
很简单,需要在AndroidManifest文件中增加一个receiver节点,并且在节点中嵌套一个intent-filter来声明组件响应的
Intent对象的属性,在autorun例子中,为系统广播android.intent.action.BOOT_COMPLETED的应用权限的声
明。
g、深入消息处理
广播消息的发送方式由多种:
无序广播
有序广播
持续广播
h、BroadcastReceiver的生命周期
BroadcastReceiver
的onReceive()方法执行完成后,BroadcastReceiver的实例就会被销毁。如果onReceive()方法在10s内没有执行完
毕,Android会认为改程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否则会弹出“Application
NoResponse”对话框。特别说明的是,这里不能使用子线程来解决
,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时它所在的进程很容易在系统需要内存时被优先杀死,因为它属于空进程。
具体实例:
http://www.apkbus.com/forum.php?mod=viewthread&tid=4406
http://www.apkbus.com/forum.php?mod=viewthread&tid=19029&reltid=4406&pre_thread_id=0&pre_pos=1&ext=
http://www.cnblogs.com/wangtianxj/archive/2010/01/20/1652480.html
接收广播BroadcastReceiver的更多相关文章
- BroadcastReceiver(接收广播)
Broadcast Receiver用于接收并处理广播通知(broadcast announcements).多数的广播是系统发起的,如地域变换.电量不足.来电来信等.程序也能够播放一个广播. 程序能 ...
- Android 广播 BroadcastReceiver
Android 系统里定义了各种各样的广播,如电池的使用状态,电话的接收和短信的接收,开机启动都会产生一个广播.当然用户也可以自定义自己的广播. 既然说到广播,那么必定有一个广播发送者,以及广播接收器 ...
- 无废话Android之activity的生命周期、activity的启动模式、activity横竖屏切换的生命周期、开启新的activity获取他的返回值、利用广播实现ip拨号、短信接收广播、短信监听器(6)
1.activity的生命周期 这七个方法定义了Activity的完整生命周期.实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环: (1)Activity的完整生命周期 自第一次调用onCrea ...
- Android广播BroadcastReceiver 一
Android 系统里定义了各种各样的广播,如电池的使用状态,电话的接收和短信的接收,开机启动都会产生一个广播.当然用户也可以自定义自己的广播. 既然说到广播,那么必定有一个广播发送者,以及广播接收器 ...
- 使用广播-BroadcastReceiver最详细解析
女孩:BroadcastReceiver是什么呀? 男孩:Broadcast是广播的意思,在Android中应用程序之间的传输信息的机制,BroadcastReceiver是接收广播通知的组件,广播和 ...
- Android数据传递,使用广播BroadcastReceiver;
Android数据传递有很多种,Intent意图传递或使用Bundle去传递,接口监听回调传递数据,也可以把数据保存起来,使用的时候去读取等等等...,"当你知道足够多的数据传递的方式之后, ...
- Android广播BroadcastReceiver
Android 系统里定义了各种各样的广播,如电池的使用状态,电话的接收和短信的接收,开机启动都会产生一个广播.当然用户也可以自定义自己的广播. 既然说到广播,那么必定有一个广播发送者,以及广播接收器 ...
- Android -- 怎么发出和接收广播, Broadcast, 电话拨号拦截,短信拦截
1. 发送广播 使用以下三个API可以发送广播 public void click(View view){ Intent intent = new Intent(); intent.setAction ...
- 广播BroadcastReceiver(2)
有序广播的优先级: 发送有序广播的方法有: public void sendOrderedBroadcast(Intent intent,String receiverPermis ...
随机推荐
- Perl正则表达式
perl正则表达式就是通过一串特别设计的字符串,可以按照我们的需求匹配.替换.转化目标字符串.本文主要是对一些常用的正则表达以及语法的总结以及举例,供广大喜爱Perl的同学交流学习. 操作符: =~ ...
- python的高阶函数
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数. 高阶函数 定义:一个函数就可以接收另一函数作为参数,这种函数就称之为高阶函数. map/reduce Python ...
- Codeforces Round #343 (Div. 2) C. Famil Door and Brackets dp
C. Famil Door and Brackets 题目连接: http://www.codeforces.com/contest/629/problem/C Description As Fami ...
- [HTML/CSS]div显示在object、embed之上~
引言 帮一个朋友弄前端布局,一切都正常,但是嵌入object之后,div总是在object的下面,就上网找了一下解决方案,这里记录一下,好像只对flash有效. 用embed插入一个flash(比如优 ...
- c语言下的变量类型及计算
源码 补码 反码 机器数:一个数在计算机中的二进制表示形式, 叫做这个数的机器数.机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1. 真值:第一位是符号位,将带符号位的 ...
- 牛x的面试知识点
已经凌晨2点多了,看来今天是失眠了,反正睡不着,写篇日记总结一下我的第一次社招面试经历吧.2015年12月1日办理了离职手续,离开了万通中心,也算是和我的第一个东家正式说了再见,其实还是很喜欢国贸的, ...
- java多线程之同一个锁和分离锁
1.对集合/共享对象的读写方法同一个锁,故无法实现读写并行.典型的就是arrayblockingQueue.数组阻塞队列 2.对同一个数据的读写方法采用分离锁,则可以实现读写并行.典型的就是linkB ...
- KEIL、uVision、RealView、MDK、KEIL C51之间比较
KEIL uVision,KEIL MDK,KEIL For ARM,RealView MDK,KEIL C51,KEIL C166,KEIL C251 从接触MCS-51单片机开始,我们就知道有一个 ...
- Android疑难杂症之KillProcess 和System.exit 无效
以下所讲,浓缩在 https://github.com/wytings/CrashDemo 首先就这个名字来说,kill了process 或者 system.exit确实已经把APP杀掉了,特别是当你 ...
- 《Go语言实战》笔记之第四章 ----数组、切片、映射
原文地址: http://www.niu12.com/article/11 ####数组 数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块. 数组存储的类型可以是内置类型,如整型 ...