总结全面的广播机制

天高空 发布于 2012/03/20 14:43
阅读 1K+
收藏 7

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.xml intent-filter 的参数。

 

< receiver android:name = ".MyBroadcastReceiver" >

           < intent-filter android:priority = "1000" >

             

< action android:name = "cn.lenovo.yangguangfu" />

</ intent-filter >

</ receiver >

 

sendOrderedBroadcast(intent, receiverPermission);

 

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

 

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;

 

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

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-permission android:name="android.permission.BROADCAST_STICKY" /> 这个权限。才能使用这个方法。如果您并不拥有该权限,将抛出 SecurityException 的。

 

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

 

广播注册与注销

代码中注册广播:

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

 

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

 

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

 

 

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

 

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

 

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

 

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

< receiver android:name = ".MyBroadcastReceiver" >

           < intent-filter android:priority = "900" >

             

              < action android: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 (boolean makeMap)

If true then a new empty Map will be made for you if the current Map is null; if false you should be prepared to receive a 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 currently processing the initial value of a sticky broadcast -- that is, the value that was last broadcast and is currently held in the sticky cache, so this is not directly the result of a broadcast right now.

 

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

 

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

 

 

isOrderedBroadcast ()

sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,

  initialCode, initialData, initialExtras)

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

判断是否是有序广播

转自:http://blog.sina.com.cn/s/blog_8984d3f301011rkp.html

加载中
0
爱长痘的汤圆
爱长痘的汤圆
你好,我有个问题想问问你,我已经吧广播的优先级设置为最高了,为什么开机自启动有时候灵有时候不灵呢?
返回顶部
顶部