android广播接收器BroadCastReceiver详解
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.xml****中intent-filter的参数。
receiverandroid:name\=_".MyBroadcastReceiver"_\
intent-filterandroid:priority\=_"1000"_\
actionandroid: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;
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,该广播的级别有级别之分,级别数值是在-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-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;
判断是否是有序广播;