Android_广播
BroadcastReceiver
一,概述
使用场景:
1.同一app内部的组件之间的消息通信
2.同一app不同进程之间的消息通信
3.不同app之间的组件之间消息通信
4.Android系统与app之间的消息通信
实现原理:观察者模式,基于消息的发布/订阅事件模型。
实现流程(大致):
1.接受者通过Binder机制向AMS(Activity Manager Service)进行注册
2.发送者通过Binder机制向AMS发送广播
3.AMS查找符合条件(IntentFilter/Permission等)的接受者,将广播发送到接受者响应的消息循环队列中
4.消息循环队列执行拿到此广播,回调接受者中的onReceive()方法
二:自定义广播
要继承BroadcastReceiver,实现onReceive(Context context,Intent intent).一般用于启动service等操作。
1 public class ChangeTimeReceiver extends BroadcastReceiver { 2 3 @Override 4 public void onReceive(Context context, Intent intent) { 5 if(DynamicService.open){ 6 DynamicService.isChange = true; 7 context.startService(new Intent(context,DynamicService.class)); 8 } 9 } 10 }
注册类型:静态注册 和 动态注册
1,静态注册
在AndroidManifest.xml中
1 <receiver 2 android:name="com.google.android.apps.analytics.AnalyticsReceiver" 3 android:exported="true" > 4 <intent-filter> 5 <action android:name="com.android.vending.INSTALL_REFERRER" /> 6 </intent-filter> 7 </receiver> 8 <!-- 修改时间广播 --> 9 <receiver android:name="com.sf.app.service.ChangeTimeReceiver" > 10 <intent-filter> 11 <action android:name="android.intent.action.TIME_SET" /> 12 </intent-filter> 13 </receiver> 14 <!-- 开机广播 --> 15 <receiver android:name="com.sf.app.service.StartNotifyReceiver" > 16 <intent-filter> 17 <action android:name="android.intent.action.BOOT_COMPLETED" /> 18 </intent-filter> 19 </receiver> 20 <receiver 21 android:name="com.sf.app.service.ConnectionChangeReceiver" 22 android:label="NetworkConnection" > 23 <intent-filter> 24 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> 25 </intent-filter> 26 </receiver> 27 <receiver android:name="com.sf.app.service.ScreenGuardReceiver" > 28 <intent-filter android:priority="90000" > 29 <action android:name="android.intent.action.USER_PRESENT" /> 30 <action android:name="com.sf.app.activity.getofflinemessage" /> 31 </intent-filter> 32 </receiver>
android:name=""--Required name of the class implementing the receiver, deriving from
android.content.BroadcastReceiver. [string]. * Required.
android:permission=""--Specify a permission that a client is required to have in order to use the associated object. [string]
android:process=""--Specify a specific process that the associated code is to run in. [string]
android:exported=""--Flag indicating whether the given application component is available to other applications. [boolean]
其默认值是由receiver中有无intent- filter决定的,如果有intent-filter,默认值为true,否则为false。(同样的,activity/service中的此属性默 认值一样遵循此规则)同时,需要注意的是,这个值的设定是以application或者application user id为界的,而非进程为界(一个应用中可能含有多个进程);
android:singleUser=""--If set to true, a single instance of this component will run for all users. [boolean]
2.动态注册:
1 //register BroadcastReceiver 2 //method 1 3 receiver = new BroadcastReceiver() { 4 @Override 5 public void onReceive(Context context, Intent intent) { 6 System.out.println("尝试收听广播"); 7 if(MyAction.equals(intent.getAction())){ 8 System.out.println("收到 SF 广播"); 9 } 10 } 11 }; 12 IntentFilter filter = new IntentFilter(MyAction); 13 manager = LocalBroadcastManager.getInstance(this); 14 manager.registerReceiver(receiver, filter); 15 //method 2 register receiver in the AndroidManifest.xml 16 // registerReceiver(receiver, filter); 17 } 18 @Override 19 protected void onDestroy() { 20 System.out.println("onDestroy"); 21 manager.unregisterReceiver(receiver); 22 super.onDestroy(); 23 }
当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中。当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。
三:发送广播及广播类型
1 Intent intent = new Intent(); 2 intent.setAction(BROADCAST_ACTION); 3 intent.putExtra("name", "qqyumidi"); 4 sendBroadcast(intent);
类型:
1.Normal Broadcast:普通广播
2.System Broadcast:系统广播
3.Ordered Broadcast:有序广播
1>多个具当前已经注册且有效的BroadcastReceiver接收有 序广播时,是按照先后顺序接收的,先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照 priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。
2>先接收的BroadcastReceiver可以对此有序广播进行截 断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,使后面的BroadcastReceiver接收到广播后解析 得到错误的参数值。当然,一般情况下,不建议对有序广播进行此类操作,尤其是针对系统中的有序广播。
4.Local Broadcast:app内广播--Android v4兼容包中给出了封装好的LocalBroadcastManager类,用于统一处理App应用内的广播问题
四:安全性:
由前文阐述可知,Android中的广播可以跨进程甚至跨App直接通信,且注册是exported对于有intent-filter的情况下默认值是true,由此将可能出现安全隐患如下:
1.其他App可能会针对性的发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收到广播并处理;
2.其他App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。
无论哪种情形,这些安全隐患都确实是存在的。由此,最常见的增加安全性的方案是:
1.对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;
2.在广播发送和接收时,都增加上相应的permission,用于权限验证;
3.发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。
App应用内广播可以理解成一种局部广播的形式,广播的发送者和接收者都同属于一个App。实际的业务需求中,App应用内广播确实可能需要用到。同时,之所以使用应用内广播时,而不是使用全局广播的形式,更多的考虑到的是Android广播机制中的安全性问题。
相比于全局广播,App应用内广播优势体现在:
1.安全性更高;2.更加高效。
五:其它
1.不同注册方式的广播接收器回调onReceive(context, intent)中的context具体类型
1).对于静态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是ReceiverRestrictedContext;
2).对于全局广播的动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Activity Context;
3).对于通过LocalBroadcastManager动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Application Context。
注:对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册的ContextReceiver才有可能接收到(静态注册或其他方式动态注册的ContextReceiver是接收不到的)。
2.以下内容不一定正确。测试的时候有异常。
”静态注册的广播接收器即使app已经退出,主要有相应的广播发出,依然可以接收到,但此种描述自Android 3.1开始有可能不再成立“
Android 3.1开始系统在Intent与广播相关的flag增加了参数,分别是FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES。
FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)
FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包
主要原因如下:
自Android3.1开始,系统本身则增加了 对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为 FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接 收到广播。
详情参加Android官方文档:http://developer.android.com/about/versions/android-3.1.html#launchcontrols
由此,对于系统广播,由于是系统内部直接发出,无法更改此intent flag值,因此,3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。
但是对于自定义的广播,可以通过复写此flag 为FLAG_INCLUDE_STOPPED_PACKAGES,使得静态注册的BroadcastReceiver,即使所在App进程已经退出,也能 能接收到广播,并会启动应用进程,但此时的BroadcastReceiver是重新新建的。
1 Intent intent = new Intent();
2 intent.setAction(BROADCAST_ACTION);
3 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
4 intent.putExtra("name", "qqyumidi");
5 sendBroadcast(intent);
注1:对于动态注册类型的BroadcastReceiver,由于此注册和取消注册实在其他组件(如Activity)中进行,因此,不受此改变影响。
注2:在3.1以前,相信不少app可能通过静态注册方式监听各种系统广播,以此 进行一些业务上的处理(如即时app已经退出,仍然能接收到,可以启动service等..),3.1后,静态注册接受广播方式的改变,将直接导致此类方 案不再可行。于是,通过将Service与App本身设置成不同的进程已经成为实现此类需求的可行替代方案。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。