1.概述
广播是Android四大组件之一,监听 / 接收 应用 App 发出的广播消息,并做出响应。
可以在Android不同组件间的通信(含 :应用内 / 不同应用之间)或多线程通信 或 Android 系统在特定情况下的通信。
一个完整的广播流程:
- 1.注册广播,创建广播接收器
- 2.发送广播,传送数据
- 3.取消注册
广播从注册方式上分为两种形式,一种是静态注册,一种是动态注册。
2.静态注册
静态注册,就是在清单文件里注册广播
<receiver
android:name=".MyReceiver"
android:enabled="true">
<intent-filter>
<action android:name="com.example.test_broadcast" />
</intent-filter>
</receiver>
广播接收器 接收到事件去处理逻辑
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
//接收事件的方法
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: "+intent.getStringExtra("msg"));
}
}
Intent intent = new Intent("com.example.test_broadcast");
intent.putExtra("msg", "我是广播数据!");
sendBroadcast(intent);
注意:静态广播没有取消注册,因为它在清单文件里注册,它是常驻形式的。
3.动态注册
动态注册意思就是在代码里注册,所以动态注册需要取消注册,一般都是界面销毁的时候。
/**
* 动态注册广播
*/
private void initRegister() {
DynamicBroadcastReceiver dynamicBroadcastReceiver = new DynamicBroadcastReceiver();
// intent过滤器 且添加action
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("I am DynamicBroadcastReceiver");
registerReceiver(dynamicBroadcastReceiver, intentFilter);
}
/**
* 动态注册广播,要使用代码注册,不能在清单文件里注册
*/
public class DynamicBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "DynamicBroadcastReceive";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: "+intent.getStringExtra("msg"));
}
}
发送广播
Intent dynamicIntent = new Intent();
dynamicIntent.setAction("I am DynamicBroadcastReceiver");
dynamicIntent.putExtra("msg", "我是动态的广播");
sendBroadcast(dynamicIntent);
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(dynamicBroadcastReceiver);
}
3.1静态和动态注册的区别
- 静态注册是常驻型,在清单文件里注册。不受组件生命周期的影响。也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
- 动态注册广播不是常驻型广播,动态广播比静态广播优先级高。灵活,跟随组件的生命周期变化。也就是说广播跟随activity的生命周期。注意: 在activity结束前,取消注册。
4.本地广播
普通的Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认值为true)
-
可能出现的问题:
其他App针对性发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收广播并处理;
其他App注册与当前App一致的intent-filter用于接收广播,获取广播具体信息;即会出现安全性 & 效率性的问题。 -
解决方案
使用App应用内广播(Local Broadcast),也叫本地广播。 -
区别:
1.App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。
2.相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高
1.创建本地广播接收器
BroadcastReceiver localBroadCast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: "+intent.getStringExtra("hh"));
}
};
2.注册本地广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("xx.yy.zz");
LocalBroadcastManager.getInstance(this).registerReceiver(localBroadCast,intentFilter);
3、取消注册本地广播
LocalBroadcastManager.getInstance(this).unregisterReceiver(localBroadCast);
4、发送本地广播
Intent intent = new Intent();
intent.putExtra("hh","hello");
intent.setAction("xx.yy.zz");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
5.系统广播
系统广播就是系统已经预制了很多和系统有关得广播。如关闭屏幕,打开屏幕,电量变化。
5.1每个广播都有特定的Intent - Filter(包括具体的action)
5.2 只能动态注册的广播:
android.intent.action.SCREEN_ON//屏幕打开
android.intent.action.SCREEN_OFF//屏幕关闭
android.intent.action.BATTERY_CHANGED//电量变化
android.intent.action.CONFIGURATION_CHANGED//设备的配置信息已经改变
android.intent.action.TIME_TICK//时间相关的广播
android.net.conn.CONNECTIVITY_CHANGE//网络状态发生改变,Android7.0之后只能动态注册
6.有序广播
发送出去的广播被多个广播接收者按照先后顺序接收,有序是针对广播接收者而言的。
广播接受者接收广播的顺序规则(同时面向静态和动态注册的广播接受者)
按照Priority属性值从大-小排序;数值越大,优先获取信息。
Priority属性相同者,动态注册的广播优先;
特点
接收广播按顺序接收
先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;
先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播
发送有序广播
sendOrderedBroadcast(intent);
private void register() {
one = new OneReceiver();
IntentFilter intentFilter2 = new IntentFilter();
intentFilter2.setPriority(0);
intentFilter2.addAction("com");
registerReceiver(one, intentFilter2);
two = new TwoReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.setPriority(1000);
intentFilter.addAction("com");
registerReceiver(two, intentFilter);
three = new ThreeReceiver();
IntentFilter intentFilter3 = new IntentFilter();
intentFilter3.setPriority(-1000);
intentFilter3.addAction("com");
registerReceiver(three, intentFilter3);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(one);
unregisterReceiver(two);
unregisterReceiver(three);
}
7.注意
对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的:
对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context。
对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;
在广播中启动activity的话,需要为intent加入FLAG_ACTIVITY_NEW_TASK的标记,不然会报错,因为需要一个栈来存放新打开的activity。
广播中弹出AlertDialog的话,需要设置对话框的类型为:TYPE_SYSTEM_ALERT不然是无法弹出的。