android的广播机制主要有两个角色,广播发送和接收者(BroadcastReceiver)。在android开发中广播的使用有很多。
1.同一app内部的同一组件内的消息通信(单个或多个线程之间);
2.同一app内部的不同组件之间的消息通信(单个进程);
3.同一app具有多个进程的不同组件之间的消息通信;
4.不同app之间的组件之间消息通信;
5.Android系统在特定情况下与App之间的消息通信。
比如一个很常见的GPS定位功能,如果需要获取实时经纬度,可以注册一个广播来接收。
如果按照广播的传递来分类,可以分为有序广播和无序广播。
有序广播:OrderedBroadcast
有序广播发出以后,同一时刻只能有一个广播接收器收到这条广播。优先级高的广播先接受到这条
广播。在当前广播接收器处理完自己的逻辑以后,可以执行两种动作:
1
.继续传递广播 2.将广播截断
无序广播:普通广播
无序广播会被注册了的相应的感兴趣(intent-filter匹配)接收,且顺序是无序的。如果发送广播时有相应的权限要求,BroadCastReceiver如果想要接收此广播,也需要有相应的权限。
无序广播的广播接收者不可以使用setResultData()方法和abortBroadcast()方法,如果使用了会报错。 但是可以使用getResultData()方法,虽然不报错,但是获取到的数据为null。但是在一种<u>特殊情况</u>下,getResultData()方法能取到无序广播传递的数据,下文会说明在什么情况下。
无序广播不可以被拦截,不可以被终止,不可以被修改,无序广播任何接收者只要匹配条件都可以接收到,无优先级问题。
如果想通过无序广播传递数据,则可以调用intent.putExtra方法传递, 接收者可通过intent.get...接收,不可通过getResultData接收。
无序广播的注册有两种方式
动态注册:
在代码中注册的广播,被称为动态注册。动态注册的广播,最后必须取消注册。这类广播,只有应用启
动了,才能接收到广播。
下面直接
来看动态注册的核心代码
public
class
MainActivity
extends
AppCompatActivity {
// 决定广播接收器接收什么广播
private
IntentFilter intentFilter ;
private
NetworkChangeReceiver networkChangeReceiver ;
private
TextView txt_show ;
private
Button btn_isNetConnect ;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取控件实例
txt_show = (TextView) findViewById(R.id.txt_show);
btn_isNetConnect = (Button) findViewById(R.id.btn_isNetConnect);
// 在按钮监听器中注册广播
btn_isNetConnect.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
intentFilter =
new
IntentFilter() ;
// 字符串 android.net.conn.CONNECTIVITY_CHANGE (这里属于系统级的广播要用指定的字符串,如果非系统广播,可以自定义字符串,也是广播接收的唯一标示)
// 表明广播接收器接收网络变化的广播
intentFilter.addAction(
"android.net.conn.CONNECTIVITY_CHANGE"
);
// 网络变化广播接收器实例
networkChangeReceiver =
new
NetworkChangeReceiver() ;
// 注册广播
// 别忘了,申明权限
registerReceiver(networkChangeReceiver,intentFilter) ;//动态注册
}
});
}
/**
* 动态注册的广播,必须在取消注册。
* 我们在create(),方法创建的时候,注册了广播
* 这里,我们在销毁活动中,取消注册,
* 当然也可以在onPause()方法取消注册。
*/
@Override
protected
void
onDestroy() {
super
.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
/**
* 用内部类实现一个网络变化广播接收器
*/
class
NetworkChangeReceiver
extends
BroadcastReceiver {
// 重写父类的onReceive()方法,接收到对应的广播的时候,就会回调这个方法
// 广播接收器的处理逻辑,就写此方法中
@Override
public
void
onReceive(Context context, Intent intent) {
// 获取网络管理服务类,就跟findViewById()方法一样
ConnectivityManager connectivityManager =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
// 记住这样写。就好了。用到的时候,百度一下,边边角角,谁也记不清
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo() ;
// 判断网络状态
if
(networkInfo !=
null
&& networkInfo.isAvailable()){
txt_show.setText(
"当前网络可用"
);
}
else
{
txt_show.setText(
"当前网络不可用"
);
}
}
}
}
静态注册:
相比于动态注册,静态注册比较简单,需要在主配置文件AndroidManifest.xml中注册。
代码:
<receiver android:name="com.hua.bcreceiver.MyBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.MY_BROADCAST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
发送普通广播:
// 自定义广播内容
String broadcast =
"allbet.broad.cn.broadcasttest.MY_BROADCAST"
;
// 绑定到Intent中
Intent intent =
new
Intent(broadcast) ;
// 发送广播,调用Context的sendBroadcast()方法
sendBroadcast(intent);
发送有序广播:
// 自定义广播内容
String broadcast =
"allbet.broad.cn.broadcasttest.MY_BROADCAST"
;
// 绑定到Intent中
Intent intent =
new
Intent(broadcast) ;
// 发送有序广播
// 第一个参数依然是Intent
// 第二个参数是代表权限的字符串,这里写null就好了
sendOrderedBroadcast(intent,
null
);
截断有序广播:
有序广播在传送中,是可以被截断,甚至可以修改广播携带的数据。
在receiver方法中使用abortBroadcast()方法进行截断。
本地广播:
之前我们发送的广播,都是系统全局广播,即我们发送的广播,能被系统的其他程序也接收到。这样是
很不安全的,因为,广播上说不定会携带着关键数据。或者,其他程序,不停的向我们发生垃圾广播。
本地广播是无法通过静态注册的广播接收者接收到
// 获取本地广播管理 实例
localBroadcastManager = LocalBroadcastManager.getInstance(
this
);
intentFilter =
new
IntentFilter(
"com.mjc.yydd"
) ;
myLocalBr =
new
MyLocalBr() ;
localBroadcastManager.registerReceiver(myLocalBr,intentFilter);
break
;
注意事项:
1.不要在onReceiver方法中进行耗时操作,否则会ANR
2.在动态注册后一定要及时通过unrejester方法进行反注册,否则会造成内存泄露,也有可能会报too many broadcast receiver regist exception。值得一提的是,华为手机的android5.0和5.1版本,系统只提供500个广播接收者,也就是说当你连续注册且不解绑到501个广播时,就会抛出此异常,往上的版本可以上万个。