Android中定件义了很多很多的事件如,电话打出去了,电量变化了,信号变化了,应用安装了,屏幕开启了关闭了,当这些事件到来的时候;android就会发送广播如果想到监听到这些事件,就需要注册广播接收者,主要为了方便开发者进行开发。
内部实现机制:
广播接收者的用法
public class SdcradReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//
//
//一个广播接收者 可以同时注册多个广播的接受事件
//通过action去区分
//获取action 通过intent
String action = intent.getAction();
if (action.equals("android.intent.action.MEDIA_MOUNTED")) {
System.out.println("sd卡 安装成功");
}
if (action.equals("android.intent.action.MEDIA_UNMOUNTED")) {
System.out.println("sd卡 卸载了");
}
Uri data = intent.getData();
System.out.println(data);
}
}
清单代码:
<receiver android:name="cn.test.sdcard.SdcradReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
<data android:scheme="file" />
intent-filter>
receiver>
无序广播:相当于新闻联播7点钟准时开始放不能配置优先权,广播不能被中断,系统广播一般是无序广播
实现广播接收类:
public class NormalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String data = intent.getStringExtra("news");
Toast.makeText(context, data, 0).show();
}
}
清单文件注册广播接收:
<receiver android:name="cn.test.receivenormal.NormalReceiver">
<intent-filter >
<action android:name="cn.test.news"/>
intent-filter>
receiver>
发送广播:
Intent intent=new Intent();
//为了让广播接收者 有接收到的action
intent.setAction("cn.test.news");
intent.putExtra("news", "新闻联播每天晚上7点准时与您相约,不见不散哦");
sendBroadcast(intent);
有序广播:红头文件 可以配置优先权.广播是可以中断的
背景介绍:
发送一个有序广播,有多个广播接收者,分别为 CityReceiver TownReceiver FarmerReceiver 以及最终的广播接收者ResultReceiver(返回有序广播的接受情况)
申明多个广播接受着:
public class CityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String data = getResultData();
Toast.makeText(context, "市政府收到的信息:"+data, 0).show();
setResultData("皇上给灾民赈灾粮20万石");
}
}
public class TownReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String data = getResultData();
Toast.makeText(context, "镇政府收到的信息:"+data, 0).show();
setResultData("皇上给灾民赈灾粮10万石");
}
}
public class FarmerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String data = getResultData();
Toast.makeText(context, "灾民收到的信息:" + data, 0).show();
}
}
再定义这三个广播接收者的清单:
<receiver android:name="cn.test.receiveorder.CityReceiver">
//优先级 0-1000
<intent-filter android:priority="1000">
<action android:name="cn.daqing.rice"/>
intent-filter>
receiver>
<receiver android:name="cn.test.receiveorder.TownReceiver">
<intent-filter android:priority="666">
<action android:name="cn.daqing.rice"/>
intent-filter>
receiver>
<receiver android:name="cn.test.receiveorder.FarmerReceiver">
<intent-filter android:priority="110">
<action android:name="cn.daqing.rice"/>
intent-filter>
receiver>
定义最终的广播接收者,自己的广播接收者,该接受者不需要在清单文件中配置,主要由于向发送广播者反应发送的广播最终情况,这个可以根据自己发送有序广播参数选择是否添加:
public class ResultReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String data = getResultData();
Toast.makeText(context, "报告皇上灾民收到信息是:"+data, 0).show();
}
}
发送有序广播
Intent intent=new Intent();
intent.setAction("cn.daqing.rice");
ResultReceiver resultReceiver = new ResultReceiver();
//receiverPermission 接受的权限
//resultReceiver 结果接收者 最终的广播接收者 自己的广播接收者 不需要在清单文件中配置
//广播被优先级高的 中断 依然可以收到广播 最后收到广播
//scheduler handler
//initialData 初始化的数据
//initialExtras 额外的数据
// sendOrderedBroadcast(Intent intent,
// String receiverPermission,
// BroadcastReceiver resultReceiver,
// Handler scheduler,
// int initialCode,
// String initialData,
// Bundle initialExtras)
sendOrderedBroadcast(intent, null, resultReceiver, null, RESULT_OK, "皇上给灾民赈灾粮50万石",
null);
注意:abortBroadcast(),进行广播拦截的时候 是不能拦截最终的广播(resultReceiver )。
- 优先级相同
不同应用 谁先在手机中安装 谁先接受到信息
同一应用 谁先在清单文件中注册 谁先接收到信息
- 优先级不同
不管应用是否相同 都是 按优先级的顺序接受广播
以上广播注册都是在清单文件中进行注册(静态注册)的,而操作非常频繁广播,比如屏幕的关闭和开启电池电量的变化不能直接在清单文件中注册
,这时需要动态的在代码中注册一般在 onCreate()方法中注册,并把receiver声明成全局变量,最后在onDestory()中注销
即:
public class MainActivity extends Activity {
private ScreenReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//代码 动态的注册广播接收者
// /receiver 要注册 广播接收者
//filter 过滤器
receiver = new ScreenReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("android.intent.action.SCREEN_ON");
filter.addAction("android.intent.action.SCREEN_OFF");
registerReceiver(receiver, filter);
}
//当activity销毁的时候调用
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(receiver);
}
}
广播接收者:
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.intent.action.SCREEN_ON")) {
System.out.println("屏幕亮了");
}
if (action.equals("android.intent.action.SCREEN_OFF")) {
System.out.println("屏幕灭了");
}
}
}
LocalBroadcastManager是Android Support包提供了一个工具,用于在同一个应用内的不同组件间发送Broadcast。LocalBroadcastManager也称为局部通知管理器,这种通知的好处是安全性高,效率也高,适合局部通信,可以用来代替Handler更新UI
好处:
1、因广播数据在本应用范围内传播,你不用担心隐私数据泄露的问题。 2、不用担心别的应用伪造广播,造成安全隐患。 3、相比在系统内发送全局广播,它更高效。
LocalBroadcastManager用法
1、LocalBroadcastManager对象的创建
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance( this ) ;
2、注册广播接收器
LocalBroadcastManager.registerReceiver( broadcastReceiver , intentFilter );
3 、发送广播
LocalBroadcastManager.sendBroadcast( intent ) ;
4、取消注册广播接收器
LocalBroadcastManager.unregisterReceiver( broadcastReceiver );
private static LocalBroadcastManager mInstance;
public static LocalBroadcastManager getInstance(Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
mAppContext = context;
mHandler = new Handler(context.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_EXEC_PENDING_BROADCASTS:
executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
从这个部分源码可以看出两点:
1、在获取LocalBroadcastManager对象实例的时候,这里用了单例模式。并且把外部传进来的Context 转化成了ApplicationContext,有效的避免了当前Context的内存泄漏的问题。这一点我们在设计单例模式框架的时候是值得学习的,看源码可以学习到很多东西。
2、在LocalBroadcastManager构造函数中创建了一个Handler.可见 LocalBroadcastManager 的本质上是通过Handler机制发送和接收消息的。
3、在创建Handler的时候,用了 context.getMainLooper() , 说明这个Handler是在Android 主线程中创建的,广播接收器的接收消息的时候会在Android 主线程,所以我们决不能在广播接收器里面做耗时操作,以免阻塞UI。
public class MainActivity extends AppCompatActivity {
private LocalBroadcastManager localBroadcastManager ;
private MyBroadcastReceiver broadcastReceiver ;
private IntentFilter intentFilter ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册广播接收器
localBroadcastManager = LocalBroadcastManager.getInstance( this ) ;
broadcastReceiver = new MyBroadcastReceiver() ;
intentFilter = new IntentFilter( "myaction") ;
localBroadcastManager.registerReceiver( broadcastReceiver , intentFilter );
//在主线程发送广播
Intent intent = new Intent( "myaction" ) ;
intent.putExtra( "data" , "主线程发过来的消息" ) ;
localBroadcastManager.sendBroadcast( intent ) ;
new Thread(new Runnable() {
@Override
public void run() {
//在子线程发送广播
Intent intent = new Intent( "myaction" ) ;
intent.putExtra( "data" , "子线程发过来的消息" ) ;
localBroadcastManager.sendBroadcast( intent ) ;
}
}).start(); ;
}
private class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction() ;
if ( "myaction".equals( action )){
Log.d( "tttt 消息:" + intent.getStringExtra( "data" ) , "线程: " + Thread.currentThread().getName() ) ;
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//取消注册广播,防止内存泄漏
localBroadcastManager.unregisterReceiver( broadcastReceiver );
}
}
运行结果
D/tttt 消息:主线程发过来的消息: 线程: main
D/tttt 消息:子线程发过来的消息: 线程: main
可以看出,广播接收器的onReceive方法运行在主线程。
注意事项
虽然LocalBroadcastManager也通过BroadcastReceiver来接收消息,但是他们两个之间还是有很多区别的。
原因:随着android版本的提高,android的安全性,隐私性不断增强。
相同点: 如果进程被系统杀掉 广播接收者 在广播到来的时候依然起作用 会重启进程