android广播接收器BroadCastReceiver详解

泡在网上的日子 / 文 发表于2013-06-21 00:48 次阅读 广播

BroadCastReceiver简介

BroadCastReceiver源码位于:framework/base/core/java/android.content.BroadcastReceiver.java


广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。


广播是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的广播进行过滤接收并响应的一类组件;


来自普通应用程序,如一个应用程序通知其他应用程序某些数据已经下载完毕。

BroadcastReceiver自身并不实现图形用户界面,但是当它收到某个通知后,BroadcastReceiver可以启动Activity作为响应,或者通过NotificationMananger提醒用户,或者启动Service等等。

BroadCastReceiver的机制

1.机制

在 Android 里面有各种各样的广播,比如电池的使用状态,电话的接收和短信的接收都会产生一个广播,应用程序开发者也可以监听这些广播并做出程序逻辑的处理。如图:



2.实现

用接收短信举例:

第一种方式

实现

public class MyBroadcastReceiver extends BroadcastReceiver {
                                                                
    // action 名称
    String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED" ;
                                                                
    public void onReceive(Context context, Intent intent) {
                                                                
       if (intent.getAction().equals( SMS_RECEIVED )) {
           // 相关处理 : 地域变换、电量不足、来电来信;
       }
    }
}

系统注册:在AndroidManifest.xml中注册

< receiver android:name = ".MyBroadcastReceiver" >
           < intent-filter android:priority = "1000" >
                                                          
< action android:name = " android.provider.Telephony.SMS_RECEIVED" />
           </ intent-filter >
       </ receiver > 当然了需要权限 :
                                              
< uses-permission android:name = "android.permission.RECEIVE_SMS" />
< uses-permission android:name = "android.permission.SEND_SMS" />

第二种方式:

// 广播接收者 - 广播的接收
private BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver() {
                                      
       @Override
       public void onReceive(Context context, Intent intent) {
           // 相关处理,如收短信,监听电量变化信息
       }
                                      
    };

代码中注册:

IntentFilter intentFilter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED " );
registerReceiver( mBatteryInfoReceiver , intentFilter);

3.生命周期


描述了Android 中广播的生命周期,其次它并不像Activity 一样复杂,运行原理很简单如下图:



生命周期只有十秒左右,如果在onReceive()内做超过十秒内的事情,就会报错


每次广播到来时,会重新创建BroadcastReceiver对象,并且调用onReceive()方法,执行完以后,该对象即被销毁.当onReceive()方法在10秒内没有执行完毕,Android会认为该程序无响应.所以在

BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No

Response)的对话框.。(如图):


怎么用好BroadcastReceiver

如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成.这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束

BroadcastReceiver就先结束了.BroadcastReceiver一旦结束,此时BroadcastReceiver的

所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程).如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死.所以采用子线程来解决是不可靠的.

广播类型及广播的收发

广播类型

普通广播(Normal broadcasts)

发送一个广播,所以监听该广播的广播接收者都可以监听到改广播。

异步广播,当处理完之后的Intent,依然存在,这时候registerReceiver(BroadcastReceiver,IntentFilter)还能收到他的值,直到你把它去掉,不能将处理结果传给下一个接收者,无法终止广播.


有序广播(Ordered broadcasts)

按照接收者的优先级顺序接收广播,优先级别在intent-filter中的priority中声明,-1000到

1000之间,值越大,优先级越高.可以终止广播意图的继续传播.接收者可以篡改内容.




广播的收发

该组件接收被广播的intent,Context可以通过sendBroadcast()和sendOrderedBroadcast()

方法实现广播的发送.

首先在需要发送信息的地方,把要发送的信息和用于过滤的信息(如Action、Category)装入一个Intent对象,然后通过调用 Context.sendBroadcast()、sendOrderBroadcast()或sendStickyBroadcast()方法,把 Intent对象以广播方式发送出去。


使用sendBroadcast()或sendStickyBroadcast()方法发出去的Intent,所有满足条件的BroadcastReceiver都会随机地执行其onReceive()方法

普通广播的发送和接收:

sendBroadcast(intent);


Intent intent = new Intent("cn.lenovo.yangguangf");

sendBroadcast(intent);

priority:这个是AndroidManifest.xmlintent-filter的参数。


<receiverandroid:name=".MyBroadcastReceiver">

<intent-filterandroid:priority="1000">

<actionandroid:name="cn.lenovo.yangguangfu"/>

</intent-filter>

</receiver>


sendOrderedBroadcast(intent,receiverPermission);

1,他决定该广播的级别,级别数值是在-10001000之间,值越大,优先级越高;


2,同级别接收是先后是随机的;级别低的收到广播;

3,在android系统中只要监听该广播的接收者,都能够收到sendBroadcast(intent)发出的广播;


3,不能截断广播的继续传播,


4,实验现象,在这个方法发来的广播中,代码注册方式中,收到的广播的先后和注明优先级最高的他们的先后是随机。如果都没有优先级,代码注册收到为最先。





有序广播的发送和接收:

sendOrderedBroadcast(intent,receiverPermission);

sendOrderedBroadcast(intent,receiverPermission, resultReceiver,

scheduler, initialCode, initialData, initialExtras)

意图,广播,所有匹配的这一意图将接收机接收广播。

receiverPermission这是权限,一个接收器必须持以接收您的广播。如果为null,不经许可的要求。
resultReceiver您自己BroadcastReceiver来当作最后的广播接收器。
调度自定义处理程序,用以安排resultReceiver回调;如果为null将语境中的主线程举行。
initialCode一种结果代码的初始值。通常为Activity.RESULT_OK。这个值是-1;为其他int型也可以,如0,1,2;
initialData一种结果数据的初始值。通常情况下为空,是String类型;
initialExtras一种结果额外的初始值。通常情况下为空,是Bundle;


intent The Intent to broadcast;all receivers matching this Intent will receive the broadcast.

receiverPermission String naminga permissions that a receiver must hold in order to receive your broadcast. Ifnull, no permission is required.

resultReceiver Your ownBroadcastReceiver to treat as the final receiver of the broadcast.

scheduler A custom Handler withwhich to schedule the resultReceiver callback; if null it will be scheduled inthe Context's main thread.

initialCode An initial value forthe result code. Often Activity.RESULT_OK.

initialData An initial value forthe result data. Often null.

initialExtras An initial valuefor the result extras. Often null.




1,该广播的级别有级别之分,级别数值是在-10001000之间,值越大,优先级越高;

2,同级别接收是先后是随机的,再到级别低的收到广播;

3,同级别接收是先后是随机的,如果先接收到的把广播截断了,同级别的例外的接收者是无法收到该广播的。(abortBroadcast()


4,能截断广播的继续传播,高级别的广播收到该广播后,可以决定把该钟广播是否截断掉。

5,实验现象,在这个方法发来的广播中,代码注册方式中,收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没有优先级,代码注册收到为最先。



异步广播的发送和接收:

sendStickyBroadcast(intent);

当处理完之后的Intent,依然存在,直到你把它去掉。

发这个广播需要权限<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

去掉是用这个方法removeStickyBroadcast(intent);但别忘了在执行这个方法的应用里面AndroidManifest.xml同样要加上面的权限;



sendStickyOrderedBroadcast(intent,resultReceiver, scheduler,

initialCode, initialData,initialExtras)

这个方法具有有序广播的特性也有异步广播的特性;



发送这个广播要:<uses-permissionandroid:name="android.permission.BROADCAST_STICKY" />这个权限。才能使用这个方法。如果您并不拥有该权限,将抛出SecurityException的。


实验现象(sendStickyOrderedBroadcast()中),在这个方法发来的广播中,代码注册方式中,收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没有优先级,代码注册收到为最先。


广播注册与注销

代码中注册广播:

注册广播方法一:registerReceiver(BroadcastReceiverreceiver, IntentFilter filter),第一个参数是我们要处理广播的BroadcastReceiver(广播接收者,可以是系统的,也可以是自定义的);第二个参数是意图过滤器。


注册广播方法二:registerReceiver(receiver, filter, broadcastPermission, scheduler),第一个参数是BroadcastReceiver(广播接收者,可以是系统的,也可以是自定义的);第二个参数是意图过滤器;第三个参数是广播权限;第四个参数是Hander;


注意:权限重复现象,如果功能清单文件里注册了权限,在该方法再注册,则receiver无法收到广播,如果功能清单文件里没有注册了权限,该方法注册也无法收到。当该方法没有注册权限,功能清单里注册的时候,receiver能收到广播。



总结:在Activity中代码注册广播建议在:onResume()中注册;


思维拓展:1,如果在代码调用registerReceiver(BroadcastReceiverreceiver, IntentFilter filter)十次(receiver,filter的参数是同一参数),那么是否当该广播发送来的时候会收到十次呢?


2,注销是否也要注销十次才能把广播全部注销呢?


系统中注册广播:(在AndroidManifest.xml中)

<receiverandroid:name=".MyBroadcastReceiver">

<intent-filterandroid:priority="900">

<actionandroid:name="cn.lenovo.yangguangfu"/>

</intent-filter>

</receiver>


有时候还要根据发送广播是否指定权限,来决定是否要权限;


广播注销


//代码中注销广播

/unregisterReceiver(mBatteryInfoReceiver);




在Activity中代码注销广播建议在:onPuase()中注销;

不要这这里面注销Activity.onSaveInstanceState(),因为这个方法是保存Intent状态的。





BroadCastReceiver的API

abortBroadcast():

这个方法可以截获由sendOrderedBroadcast()发送来的广播,让其它广播接收者无法收到这个广播。

clearAbortBroadcast()

这个方法是针对上面的abortBroadcast()方法的,用于取消截获广播。这样它的下一级广播接收者就能够收到该广播了。

getAbortBroadcast()

这个方法作用是:判断是否调用了abortBroadcast(),如果先调用abortBroadcast(),接着再调用getAbortBroadcast(),将返回true; 如果在调用abortBroadcast()、clearAbortBroadcast()

getAbortBroadcast(),将返回false;

public final boolean getDebugUnregister()

Since: API Level 1

Return the last value given to setDebugUnregister(boolean).



getResultCode()

如果用下面四个方法发送得广播,返回码为:-1;

// sendBroadcast(intent);

// sendBroadcast(intent,receiverPermission);

//sendOrderedBroadcast(intent, receiverPermission);

// sendStickyBroadcast(intent);

如果用下面两个方法发送得广播,返回码为:根据你设置initialCode的数字是多少就是多少;

//sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,

// initialCode, initialData,initialExtras)

//sendOrderedBroadcast(intent, receiverPermission, resultReceiver,

// scheduler, initialCode, initialData,initialExtras)



getResultData()

得到发送广播时设置的initialData的数据;



getResultExtras(booleanmakeMap)

If true then a new empty Map will be madefor you if the current Map is null; if false you should be prepared to receivea null Map.

得到由

sendStickyOrderedBroadcast(intent,resultReceiver, scheduler,

// initialCode, initialData,initialExtras)


//sendOrderedBroadcast(intent, receiverPermission, resultReceiver,

// scheduler, initialCode, initialData, initialExtras)

initialExtras传入的参数。

实验:我用上面两个方法发了initialExtras(这个一个Bundle)传入的参数时,只要不为空,那么makeMap是否为true和false都能够得到数据。


isInitialStickyBroadcast()

Returns true if the receiver is currentlyprocessing the initial value of a sticky broadcast -- that is, the value thatwas last broadcast and is currently held in the sticky cache, so this is notdirectly the result of a broadcast right now.


如果广播接收者是目前处理的一个宿主的广播的初始值,将返回true,- 也就是说,这个值是最后的广播出的值,目前正在举行的宿主缓存,所以这并不是直接导致了现在的广播。


实验:在第三个应用中调用这个方法,无论你用哪种方式发送广播,这个方法得到的总是false;在发送广播的resultReceiver广播接收者里面调用,得到的也是false



isOrderedBroadcast()

sendStickyOrderedBroadcast(intent,resultReceiver, scheduler,

initialCode, initialData, initialExtras)

上面这个方法发送时,得到的是true;

判断是否是有序广播;


原文出处:http://yangguangfu.iteye.com/blog/1063732 

收藏 赞 (4) 踩 (0)
上一篇:Android中使用ant混淆编译
搞了好几天,查看了上百个网站,最后摸索出一套很简单的ant混淆编译的方法。下面开始: 1.拿一个普通项目来说,首先为它加上ant编译功能。 android update project --name project_name -t 3 -p D:/temp/project_name 此时会在项目根目录自动生成一个名为bui
下一篇:认识安卓中的MIME Type
MIME type 的缩写为 (Multipurpose Internet Mail Extensions) 代表互联网媒体类型 (Internet media type) , MIME 使用一个简单的字符串组成,最初是为了标识邮件 Email 附件的类型,在 html 文件 中可以使用 content-type 属性表示,描述了文件类型的互联