概念
用来互相通信(传递信息)的一种机制
- 应用内通信
- 进程通信
扩展1 Intent
Intent详解http://www.cnblogs.com/smyhvae/p/3959204.html
Intent的相关属性:
- Intent由以下各个组成部分:
- component(组件):目的组件
- action(动作):用来表现意图的行动
- category(类别):用来表现动作的类别
- data(数据):表示与动作要操纵的数据
- type(数据类型):对于data范例的描写
- extras(扩展信息):扩展信息
- Flags(标志位):期望这个意图的运行模式
Intent类型分为显式Intent(直接类型)、隐式Intent(间接类型)。官方建议使用隐式Intent。上述属性中,component属性为直接类型,其他均为间接类型。
扩展2 exported
android:exported 是Android中的四大组件 Activity,Service,Provider,Receiver 四大组件中都会有的一个属性。
总体来说它的主要作用是:是否支持其它应用调用当前组件。
默认值:如果包含有intent-filter 默认值为true; 没有intent-filter默认值为false。
即置为true表示可以被其他组件来调用。
扩展3 Bundle
Bundle在Android开发中非常常见,它的作用主要时用于传递数据。Bundle传递的数据包括:string、int、boolean、byte、float、long、double等基本类型或它们对应的数组,也可以是对象或对象数组。当Bundle传递的是对象或对象数组时,必须实现Serialiable或Parcelable接口。
Bundle所保存的数据是以key-value(键值对)的形式保存在ArrayMap中。
发送广播
发送者 ---------Intent------------ >BroadcastReceiver
Intent intent = new Intent();
intent.setAction(ACTION_UPLOAD_RESULT);
intent.putExtra(KEY_RESULT, filePath);
sendBroadcast(intent);
接收广播
用BroadcastReceiver类,继承该类或者直接new出来,在onReceive()方法里写接收之后的操作。
创建完还需要注册(静态在Manifest,动态用Context的registerReceiver()方法)这个接收器,配置这个Action,过滤广播信息。
一个应用场景:编辑消息,编辑完成之后,发送广播通知
广播分类
- 静态广播,是在Manifest文件中注册的广播。
- 常驻内存中,可在App未启动时就监听广播,如监听短信、系统时间等系统广播事件。
- 动态广播,是在代码中注册以及解除注册的广播。
- App启动后注册,然后才能监听。解除注册(一般是Activity销毁时)后广播也随之结束。
如果采用动态注册的方式,在onDestroy时要记得解除注册nregisterReceiver();
注意:两种广播同时注册的时候,动态广播优先于静态广播。
静态广播的注册与使用
静态广播最常用的场景,接收来自系统的广播:开机完成,电量低,设置时间,检测到插入U盘等。
安卓8.0以上禁止在后台执行,无法接受静态注册的隐式广播。需要明确指明目的地。
动态广播注册与使用
不要忘记解除注册
代码实践1
静态广播
第一步创建接收器类,
public class MyBroadCast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ToastUtil.longToast(context, "静态接收,接收到广播了!");
}
}
第二步,在Manifest里注册,还要设置过滤器来过滤action
<receiver android:name=".MyBroadCast"
android:exported="true">
<intent-filter>
<action android:name="test2"/>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
第三步,发送广播,显式的方式,需要指明packageName与携带的action
findViewById(R.id.btn_test2).setOnClickListener(v -> sendBroadcast(new Intent()
.setAction("test2").setPackage(getPackageName())));
或者,设置可后台执行的flags标志位,0x01000000(可用但不推荐,还是写包名)
动态广播
第一步还是创建接收器类(同上),或者new出来:
private MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
ToastUtil.longToast(getApplicationContext(), "接收到动态广播");
}
};
第二步,注册广播接收器,注意写Intentfilter的action。
IntentFilter filter = new IntentFilter();
filter.addAction("dongtai.test");
registerReceiver(myBroadcastReceiver, filter);
第三步,发送广播
sendBroadcast(new Intent("dongtai.test"));
别忘了在onDestroy()里解除注册。
无序广播与有序广播
按接收的顺序来区分,有无序广播和有序广播
无序广播,接收器接收顺序大致相同,随机。
有序广播则按照123的顺序依次进行接收(优先级递减)
代码实践2
无序广播
使用流程:
先新建三个接收器:
public class Receiver1 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
LogUtil.printLog("接收到广播1");
}
}
再采用静态方法在manifest里注册这三个广播接收器
<receiver
android:name=".receiver.Receiver1"
android:exported="true">
<intent-filter>
<action android:name="wuxutesst" />
</intent-filter>
</receiver>
发送广播
findViewById(R.id.btn_test3).setOnClickListener(v -> sendBroadcast(new Intent()
.setAction("wuxutesst").setPackage(getPackageName())));
有序广播
下面是静态和动态两种方法来设置优先级,使接收器成为有序广播接收器。
使用流程:
在注册的时候,将三者优先级设置为90,100,80,期望顺序为213。
还要注意,在发送广播的地方,要使用sendOrderedBroadcast(intent, permission),第一个参数还是intent,第二个参数是接收器想要接收广播所具备的permission。
findViewById(R.id.btn_test3).setOnClickListener(v ->
sendOrderedBroadcast(new Intent().setAction("wuxutesst").setPackage(getPackageName()), null));
有序广播还能设置截断方法abortBroadcast(),刚刚已经将Receiver2的优先级设置为最高的,现在在其中写一行:
public class Receiver2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
LogUtil.printLog("接收到广播2");
LogUtil.printLog("截断广播");
abortBroadcast();
}
}
当广播传到这个接收器时,被截断,后面的接收器就接收不到了。(无序广播没有这个方法)
有序广播除了阻断广播的方法,还有setResultExtras()方法,可以利用Bundle向优先级比它低的下游接收器传递信息。
用法:传递的时候,可以是上游接收器传下来的Bundle对象,也可以是new一个Bundle出来,设置完成后,继续传递到下游。
实操:
上面是在最上游,即Activity发送广播的时候,设置Bundle与Intent,以防空指针错误。
然后传到接收器2号的时候,再用setResultExtras()来追加信息(intent原有信息未抹除)。
if (intent != null) {
Bundle dataBundle = intent.getExtras();
dataBundle.putString("name", "广播接收器2号");
setResultExtras(dataBundle);
}
再下游的是接收器1号,在其中获取intent信息和上游传来的Bundle信息。
if (intent != null) {
Bundle dataBundle = intent.getExtras();
String data = dataBundle.getString("name");
LogUtil.printLog("intent传来的是:" + data);
}
Bundle newBundle = getResultExtras(true);
LogUtil.printLog("上一个接收器是:"+newBundle.getString("name"));
getResultExtras()方法里面填true,指即使上游没有传Bundle过来,在这里也会新建一个ArrayMap来存数据,防止NullPointer。
最后的结果如下图:
还可以用setResultData()方法,来直接传递字符串。
本地广播与全局广播
按照传播范围来划分。
本地广播:只在这个app内部进行传播,数据安全。
全局广播:在在整个手机所有app之间进行传播,可能有安全问题。
注意普通的广播默认是全局广播!
本地广播的使用
接收器与全局广播没有区别。
在注册的时候,只能采用动态注册的方式,即app启动后再准备接收。
还要用到一个类:LocalBroadcastManager(已经废弃,仅作了解)
解除注册:用这个manager实例来调用unregisterReceiver()