Android_广播

摘要:
BroadcastReceiver一,概述使用场景:1.同一app内部的组件之间的消息通信2.同一app不同进程之间的消息通信3.不同app之间的组件之间消息通信4.Android系统与app之间的消息通信实现原理:观察者模式,基于消息的发布/订阅事件模型。1publicclassChangeTimeReceiverextendsBroadcastReceiver{23@Override4publicvoidonReceive{5if{6DynamicService.isChange=true;7context.startService;8}9}10}注册类型:静态注册和动态注册1,静态注册在AndroidManifest.xml中14567891011121314˂!

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 extendsBroadcastReceiver {
2 
3 @Override
4     public voidonReceive(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 = newBroadcastReceiver() {
4 @Override
5             public voidonReceive(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 = newIntentFilter(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 voidonDestroy() {
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 = newIntent();
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本身设置成不同的进程已经成为实现此类需求的可行替代方案。

免责声明:文章转载自《Android_广播》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇gulp实现公共html代码复用for循环删除数组中的元素crash问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

AlarmManager

AlarmManager 主要管理硬件时钟。 一些与时间相关的应用,如日历,闹钟等需要使用Alarm Manager的服务。Alarm manager功能相对比较简单,相关代码位于frameworks/base/core/jni/server/com_android_server_AlarmManagerService.cppframeworks/base...

Android学习使用基本界面组件(下拉框,单选框,复选框,数字转轮,滚动条)

(一)建立单选框按钮 RadioGroup和RadioButton建立单选框按钮 字符串资源文件: <resources> <string name="app_name">婚姻建议程序</string> <string name="sex">性别:</string> <...

微信公众号开发系列-获取微信OpenID

在微信开发时候在做消息接口交互的时候须要使用带微信加密ID(OpenId),下面讲讲述2中类型方式获取微信OpenID。接收事件推送方式和网页授权获取用户基本信息方式获取。 1、通过接收被动消息方式获取OpenId(接收事件推送方式)。下面事件中都能够获取到OpenID 关注/取消关注事件 用户在关注与取消关注公众号时。微信会把这个事件推送到开发人员填...

计算机常用端口一览表

1 传输控制协议端口服务多路开关选择器 2 compressnet 管理实用程序 3 压缩进程 5 远程作业登录 7 回显(Echo) 9 丢弃 11 在线用户 13 时间 15 netstat 17 每日引用 18 消息发送协议 19 字符发生器 20 文件传输协议(默认数据口) 21 文件传输协议(控制) 22 SSH远程登录协议 23 telnet ...

DeepFacelab更新:分辨率提至640,效率翻倍!

这几天又更新了,好事儿是又有新功能可以玩了,“坏事儿”是感觉又要升级设备了。其实,总的来说这次更新,对低配高配玩家都有好消息。 1. 对于高配玩家,可以跑更高像素的模型。 2. 对于低配玩家,那些跑不起的像素也能跑起来了。 下面就来说说重点更新内容: 1.  模型训练参数 resolution 的最大值从512调到了640。 ​ 这意味着对于高配玩家来说可...

魅族推送 简介 集成 MD

Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com 目录 目录魅族推送简介FAQ简洁版自定义消息推送DemoReceiver配置文件AndroidManifest.xml 魅族推...