浅谈广播
广播属于Android四大组件之一,它的主要用于APP内部组件间的通讯,负责监听、接收、分发App内部的广播消息并做响应。我还理解的比较浅显,此篇文章也是借鉴了很多文章后的产物,有错误望指出。
原理分析
实现步骤(以广播网络状态为例)
- 定义广播接受器BroadcastReceiver
- 注册广播接收器
- 发布广播
1. 定义广播接受器BroadcastReceiver
继承BroadcastReceivre
类,重写onReceive()
方法
//网络广播接受器
public class NetBroadcastReceiver extends BroadcastReceiver {
private NetEvent netEvent;
@Override
public void onReceive(Context context, Intent intent) {
//在这里写上相关的处理代码,一般来说,不要此添加过多的逻辑或者是进行任何的耗时操作
//因为广播接收器运行在UI线程,不允许开启多线程的,过久的操作就会出现报错
//因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者启动某个服务
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
int netWrokState = NetUtil.getNetWorkState(context);
if (netEvent != null)
netEvent.onNetChange(netWrokState);
}
}
}
2. 注册广播接收器
注册有两种方式:静态/动态注册
静态注册
注册方式:在AndroidManifest.xml
中通过<receive>
标签声明。
<!-- APP首次启动时,系统自动实例化 NetBroadcastReceiver 类,并将其注册到系统中 -->
<receiver
//广播接收者器的名字
android:name=".NetBroadcastReceiver " >
//用于接收网络状态改变时发出的广播
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
动态注册
注册方式:在activity
中的onResume()
方法中注册,在onPause()
方法中销毁
/*
*选择Activity生命周期方法中的onResume()和onPause()是由于
*当系统内存不足(优先级更高的应用需要内存)要回收Activity占用的资源时,
*Activity在执行完onPause()方法后就会被销毁,有些生命周期方法onStop(),onDestory()不会执行
*所以没有使用【onStart() , onStop()】或者【onCreate() ,onDestory()】
*/
@Override
protected void onResume(){
super.onResume();
// 1. 实例化BroadcastReceiver子类 & IntentFilter
NetBroadcastReceiver netBroadcastReceiver = new NetBroadcastReceiver ();
IntentFilter intentFilter = new IntentFilter();
// 2. 设置接收广播的类型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
// 3. 动态注册:调用Context的registerReceiver()方法
registerReceiver(netBroadcastReceiver , intentFilter);
}
// 当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中
// 当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。
@Override
protected void onPause() {
super.onPause();
//销毁在onResume()方法中的广播
unregisterReceiver(netBroadcastReceiver );
}
}
静态|动态注册的区别
3. 发送广播
发送广播 = 广播发送者 将此广播的“意图(Intent)”通过sendBroadcast()方法发送出去。
广播的5种类型:
- 普通广播(
Normal Broadcast
)- 系统(全局)广播(
System Broadcast
)- 有序广播(
Ordered Broadcast
)- 粘性广播(
Sticky Broadcast
) Android5.0 & API 21之后已经失效- 本地(局部)广播(
Local Broadcast
)
3.1 普通广播
开发者自身定义 intent的广播(最常用)。发送广播使用如下:
Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action
intent.setAction(BROADCAST_ACTION);
//发送广播
sendBroadcast(intent);
3.2 系统广播
Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播。
使用系统广播时不需要发送广播,只要定义和注册接收器即可。
每个Android系统广播都有特定的action:
3.3 有序广播
有序广播是针对广播接收者说的。
特点
有序广播的接收者们将按照事先生命的优先级依次接收,数越大优先级越高(取值范围:-1000~10000),优先级可以声明在<intent-filter android:priority=“n”…/>,也可以调用IntentFilter对象的setPriority设置。并且接收者可以终止传播(调用abortBroadcast()方法终止传播),一旦终止后面接收者就无法接受广播。另外,接受者可以将处理结果存入数据(可通过setResultExtras(Bundle)方法将数据存入Broadcast),当做Broadcast再传递给下一级接收者(可通过代码Bundle bundle = getResultExtras(true)获取上一级传递过来的数据)。
短信拦截原理:系统收到短信,发出的Broadcast
属于有序广播,程序就可以通过设定优先级先接收到通知,然后终止传递。
有序广播的案例:
1.首先创建两个BroadcastReceiver
。让第一个receive
接收到广播后中断。
public class HighReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("HighReceiver接受到消息");
abortBroadcast(); //中断广播,比它优先级低得广播不会再传播下去
}
}
public class LowReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("LowReceiver接受到消息");
}
}
2.然后将两个receiver
的action
在AndroidManifest.xml
文件中配置成一样的,并且设置成不同的优先级。
<receiver android:name=".HighReceiver ">
<!-- priority优先级:数字越高优先级越高 -->
<intent-filter android:priority="5" >
<action android:name="com.codingblock.myreceiver.intent.action.MyReceiver"/>
</intent-filter>
</receiver>
<receiver android:name=".LowReceiver ">
<intent-filter android:priority="4">
<action android:name="com.codingblock.myreceiver.intent.action.MyReceiver"/>
</intent-filter>
</receiver>
3.最后在MainActivity中发送广播。
public class MainActivity extends Activity {
Button btn_send_receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_send_receiver = (Button)findViewById(R.id.btn_send_receiver);
btn_send_receiver.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.codingblock.myreceiver.intent.action.MyReceiver");
sendOrderedBroadcast(intent, null);//有序广播用sendOrderedBroadcast()方法发送广播
}
});
}
}
点击按钮后只有HighReceiver接收到了消息,广播就被中断了,LowReceiver不会接收到广播。
3.4 本地广播
特点
本地广播只能用于应用内通信,本地广播携带的信息不会暴露给其他App,其他App也无法伪造广播来起欺骗你的receiver
,安全性很好,同时拥有更高的运行效率。也是需要发送应用内广播时的官方推荐。
1.可将全局广播设置成局部广播
- 全局广播可以在注册广播时将
exported
属性设置为false
,使得非本App内部发出的此广播不被接收。- 在广播发送和接收时,增设相应权限permission,用于权限验证。
- 发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中,eg:intent.setPackage(packageName)指定包名。
2.用局部广播LocalBroadcastReceiver
LocalBroadcastReceiver
不能静态注册,只能采用动态注册的方式。
在发送和注册的时候采用,LocalBroadcastManager
的sendBroadcast
方法和registerReceiver
方法
//步骤1:实例化自定义的NetBroadcastReceiver和IntentFilter
NetBroadcastReceiver netBroadcastReceiver = new NetBroadcastReceiver ();
IntentFilter intentFilter = new IntentFilter();
//步骤2:实例化LocalBroadcastManager的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//步骤3:设置接收广播的类型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册
localBroadcastManager.registerReceiver(netBroadcastReceiver, intentFilter);
//取消注册本地广播接收器
localBroadcastManager.unregisterReceiver(netBroadcastReceiver);
//发送本地广播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);