目录
- 什么是广播
- 如何使用广播
- 注册广播的方式
- 广播的类型
- 不同注册方式的广播接收器回调
- 不同Android API版本中广播机制相关API重要变迁
一.什么是广播
作为Android 4大组件之一,压力山大。
系统或者本应用程序通过发送广播的形式告诉其他app现在系统或者本app的状态
这种方式称为广播的发送
比如:老村长拿个喇叭喊话,谁家羊丢了?(发送广播的人),所有村名都听到了(其他单独的app)
二.如何使用广播
广播的三要素
- 发送广播
- 接受广播
- 处理广播
下面一一分析
如何使用广播
public class MainActivity extends AppCompatActivity {
private TestBroadCast broadCast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//发送广播
findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.模拟发送广播 (一般写的都是action条件,不用组件名)
//自定义action条件
//在任何app,只要接收器的条件是allens都可以接收数据
Intent intent = new Intent("allens");
intent.putExtra("data", "测试发送广播...");
//核心方法
sendBroadcast(intent);
}
});
//动态注册广播
findViewById(R.id.register).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 第一个参数:自定义接收器的实例化对象
* 第二个参数:构建IntentFliter条件
*/
IntentFilter filter = new IntentFilter();
//添加的action条件,匹配频道使用
filter.addAction("allens");
//设置优先级
filter.setPriority(Integer.MAX_VALUE);
broadCast = new TestBroadCast();
registerReceiver(broadCast, filter);
}
});
//取消注册
findViewById(R.id.unregister).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (broadCast != null) {
unregisterReceiver(broadCast);
broadCast = null;
}
}
});
}
}
public class TestBroadCast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String value = intent.getStringExtra("data");
Log.e("TAG","data--->" + value);
}
}
三.注册广播的方式
动态注册
在上面的例子中 可以看到 我们使用代码动态注册了广播,也动态的取消注册广播,这是一中方式,当然还有其他的方式静态注册
在manifest
中配置
参数解释
参数 | 说明 |
---|---|
intent-filter | 过滤器,筛选广播条件 |
android:name | 这里的name 要和我们发送广播的action 相同,不然收不到广播 |
android:priority | 2000到-2000 ,通过priority设置优先级 |
android:enabled | true (默认的是true)设置为true广播接收器才能够被启用,false该广播接收器会被禁止实例化(不能使用) |
android:exported | 是否能够接收来自应用程序外部的消息 |
android:icon | 定义一个代表广播接收器的图标 |
android:label | 这个属性给广播接收器设定一个用户可读的懂的文本标签 |
android:name | 这个属性值要用广播接收器的实现类的类名来设置 |
android:permission | 把消息发送给该广播接收器的广播器所必须要有的权限 |
android:process | 这个属性用于设置该广播接收器应该运行在那个进程中的进程名 |
当然这些属性,也不用全写上,更具实际情况,
参考
http://blog.csdn.net/think_soft/article/details/7583047
对比
类型 | 优点 | 缺点 |
---|---|---|
静态注册 | 常驻广播,不受生命周期影响 | 耗电,占内存 |
动态注册 | 灵活, | 必须跟随组件的生命周期,及时释放资源 |
so 继续
四. 广播的类型
普通广播(Normal Broadcast)
系统广播(System Broadcast)
有序广播(Ordered Broadcast)
粘性广播(Sticky Broadcast)
App应用内广播(Local Broadcast)
1.普通广播
定义:开发者自己定义的intent,像上面我们使用的就是普通广播
Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action
intent.setAction("自定义的action");
//发送广播
sendBroadcast(intent);
总结
1.顺序是无序的
2.需要在intent-filter
自定义action
3.如果发送广播时有相应的权限要求,BroadCastReceiver如果想要接收此广播,也需要有相应的权限
2.系统广播
Android系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相应的系统广播。如:开启启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的intent-filter,其中主要包括具体的action,系统广播发出后,将被相应的BroadcastReceiver接收。系统广播在系统内部当特定事件发生时,有系统自动发出
android 系统广播action
3.有序广播
有序广播的有序广播中的“有序”是针对广播接收者而言的,指的是发送出去的广播被BroadcastReceiver按照先后循序接收。有序广播的定义过程与普通广播无异只是其的主要发送方式变为
sendOrderedBroadcast(intent);
特点
1.按照Priority属性值从大-小排序;
2.Priority属性相同者,动态注册的广播优先;
3.先接收的BroadcastReceiver可以对此有序广播进行截断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,使后面的BroadcastReceiver接收到广播后解析得到错误的参数值。当然,一般情况下,不建议对有序广播进行此类操作,尤其是针对系统中的有序广播
4.粘性广播
定义:广播的信息内容系统会存放一段时间,任何时间内app都可以获取数据
sendStickyBroadCast
由于在Android5.0 & API 21中已经失效,相应的还有粘性有序广播,所以不建议使用,在这里也不作过多的总结。
5.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应用内广播,其特点如下
1.安全性更高;
2.更加高效
如何使用呢?
//注册应用内广播接收器
//步骤1:实例化BroadcastReceiver子类 & IntentFilter mBroadcastReceiver
mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
//步骤2:实例化LocalBroadcastManager的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//步骤3:设置接收广播的类型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
//发送应用内广播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);
五. 不同注册方式的广播接收器回调onReceive(context, intent)中的context具体类型
类型 | context具体类型 |
---|---|
静态注册的ContextReceiver | ReceiverRestricted Context |
全局广播的动态注册的ContextReceiver | Activity Context |
通过LocalBroadcastManager动态注册的ContextReceiver | Application Context |
注意:对于
LocalBroadcastManager
方式发送的应用内广播,只能通过LocalBroadcastManager
动态注册的ContextReceiver
才有可能接收到(静态注册或其他方式动态注册的ContextReceiver
是接收不到的)
六. 不同Android API版本中广播机制相关API重要变迁
Android 3.1开始
- 自Android3.1开始,静态注册的广播接收器,app已经退出,有相应的广播发出,接收不到
原因:自Android3.1开始,系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES
的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播
Android 3.1开始系统在Intent与广播相关的flag增加了参数,分别是
FLAG_INCLUDE_STOPPED_PACKAGES
:包含已经停止的包(停止:即包所在的进程已经退出)FLAG_EXCLUDE_STOPPED_PACKAGES
:不包含已经停止的包
android 5.0开始
- Android5.0/API level 21开始粘滞广播和有序粘滞广播过期,以后不再建议使用;
android 7.0开始
- 彻底没有静态注册的方式啦,哈哈 为了省电
写在最后
关于7.0 以上的广播方案,会在后面慢慢补充,实话说啊,这东西真的好好看,抽个空静下心好好研究一下,这些细节上的事情,都是平时开发时候的坑啊。。。。