[TOC]
1. 什么是BroadcastReceive?
broadcast receiver 是一个用来响应系统范围内的广播的组件。 很多广播发自于系统本身。—例如, 通知屏幕已经被关闭、电池低电量、照片被拍下的广播。 应用程序也可以发起广播。—例如, 通知其它程序,一些数据被下载到了设备.当BroadcastReceive接收到系统发送的广播时就可以直接执行相对应的操作或者弹出一些界面与用户进行交互
通过继承BroadcastReceiver来实现广播的接收和操作 ,而且每一个广播通过
Intent
对象来传递。广播可以分为两类:标准广播(Normal broadcasts)和有序广播(Ordered broadcasts)
标准广播: 是一种完全异步执行的广播,在广播发出以后几乎所有的广播接收器会在同一时刻接收到这条广播消息.
有序广播: 是一种同步执行的广播,在广播发出以后同时只能有一个广播接收器接收,当这个广播接收器中的逻辑执行完毕以后,广播才会继续传递.所有此时的广播是有优先级的,优先级高的可以先接收到这个广播,并且还可以截断这个广播,后面的广播接收器就不会接收到这个广播了.
2. 怎样使用BroadcastReceive?
需要创建一个继承自BroadcastReceiver类的子类并重写onReceive();方法
2.1 接收系统广播
动态注册: 在代码中注册广播
public class MyBroadReceive extends BroadcastReceiver{
private static final String TAG = "MyBroadReceive";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: 接收到一条广播:"+intent.getAction());
}
//实例一个广播接收器类, 重写onReceive方法,当接收到注册到广播时,被该方法调用
}
复制代码
public class MainActivity extends AppCompatActivity {
private IntentFilter mIntentFilter;
private MyBroadReceive mMyBroadReceive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
mMyBroadReceive = new MyBroadReceive();
registerReceiver(mMyBroadReceive, mIntentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mMyBroadReceive);
}
}
复制代码
需要实例一个广播接收器和IntentFilter并将希望接收到的广播添加进去,并将广播接收器和意图过滤器绑定
注意: 动态注册的广播一定要在退出之前取消注册,因为如果不取消注册的话该广播接收器将持有该activity的引用,activity在内存是不会被销毁的.严重的可能会导致内存溢出.
分析: 上面的案例是先新建一个BroadcastReceiver的子类并重写onReceive()方法;我们在活动中创建了一个IntentFilter的实例,并添加一个值为"android.intent.action.AIRPLANE_MODE"的action c ,这是当我们飞行模式发生变化时,系统会发送这样的一条广播,想监听什么广播就添加相应的action.接着创建MyBroadReceive的实例,通过registerReceiver();将IntentFilter的实例和MyBroadReceive的实例绑定起来. 这样我们就完成了广播的动态注册,不过在活动的最后需要调用unregisterReceiver();来取消广播接收器的注册.
运行程序以后,手动的开关飞行模式将会在控制台中输出
05-16 08:56:09.556 8937-8937/com.example.h.broadcast_demo1 D/MyBroadReceive: onReceive: 接收到一条广播:android.intent.action.AIRPLANE_MODE
这表明确实接收到了这样一条广播. 通过调用*.getAction();可以获取当前接收到的广播.
静态注册: 在ManiFest.xml中注册
相对于静态注册:动态注册只可以在当前程序启动的时候才可以接收到广播,而静态注册可以在程序没有开启的情况下接收广播并执行相对的逻辑操作.
新建 other/BroadercastReceiver 设置类名并将enable和exported打上勾,它就会在ManiFest.xml中自动为我们注册这个接收器.不管程序有没有打开都可以接收到这个广播 前提是要在<action .... > 中添加想要接收的广播.
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Toast.makeText(context, "接收到广播", Toast.LENGTH_LONG).show();
Log.d(TAG, "onReceive: 收到广播");
}
}
复制代码
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.AIRPLANE_MODE" />
</intent-filter>
</receiver>
复制代码
所有的静态广播接收器都是在ManiFest.xml中进行注册的,用法和activity相似
name:指定具体注册哪一个广播接收器
enabled:是否启动这个广播接收器
exported:是否在程序以后接收广播
在标签中加如相应的标签就可以接收到指定的广播了
在这个程序中,只需要重启或者将当前的程序关闭,手动开动飞行模式就可以接收到该广播.
2.2 发送自定义广播
构建一个Intent对象 并且可以把action当作参数进行初始化,通过sendBroadcast()传入intent对象来发送自定义广播,并且在MainFest.xml或Intent-Filter中添加action即可发送和接收这个广播.
发送有序广播:
新建两个接收相同广播的程序,并只在其中一个程序中发送广播,可以发现两个程序都可以接收到该广播
这个时候通过发送有序广播,并将第一个广播接收器的优先级设高,那么在广播被截断后,其他的接收器就接收不到这个广播了
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Toast.makeText(context, "接收到广播:"+intent.getAction(), Toast.LENGTH_LONG).show();
Log.d(TAG, "onReceive: 收到广播");
abortBroadcast();//广播将在这里被截断 后面的任何一个广播接收器都接收不到了
//打印出来是为了防止 运行程序时忘记看界面导致的不知道有没有接收到广播,而又要重新运行的尴尬问题
}
}
复制代码
//在活动中
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendOrderedBroadcast(new Intent("this a broadcast"),null);
}
复制代码
<!--在ManiFest.xml中定义接收的广播-->
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="this a broadcast"/>
</intent-filter>
</receiver>
复制代码
发送标准广播:
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Toast.makeText(context, "接收到广播:"+intent.getAction(), Toast.LENGTH_LONG).show();
Log.d(TAG, "onReceive: 收到广播");
//打印出来是为了防止 运行程序时忘记看界面导致的不知道有没有接收到广播,而又要重新运行的尴尬问题
}
}
复制代码
//在活动中
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendBroadcast(new Intent("this a broadcast"));
}
复制代码
通过构建意图来发送广播.
不过如果另外一个程序也接收了一个这样的广播,两个程序是可以几乎同时接收到的.
由于发送自定义广播是用Intent进行传递的而且Intent中也可以携带一些数据传递给接收器,而这就可能导致我们发送广播时附加的数据被其它程序接收到导致数据泄露.又或者程序向我们的接收器不停的发送垃圾广播,这时候就可以使用本地广播了.
2.3 使用本地广播
为了解决广播的安全性问题,Google引入了本地广播机制,使用这个机制发出的广播只能在应用程序的内部进行传递,并且广播接收器只能接收来自本程序发出的广播.
使用LocalBroadcastManager对象对广播进行管理,使发出的广播只在程序内部进行传递,并且只能被程序内的广播接收器接收.
public class MainActivity extends AppCompatActivity {
private LocalBroadcastManager mLocalBroadcastManager;
private IntentFilter mIntentFilter;
private localBroadcastReceive mLocalBroadcastReceive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction("other_broadcast");
mLocalBroadcastReceive = new localBroadcastReceive();
mLocalBroadcastManager.registerReceiver(mLocalBroadcastReceive, mIntentFilter);
Intent intent = new Intent("other_broadcast");
mLocalBroadcastManager.sendBroadcast(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
mLocalBroadcastManager.unregisterReceiver(mLocalBroadcastReceive);
}
class localBroadcastReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "本地广播:"+intent.getAction(), Toast.LENGTH_SHORT).show();
}
}
}
复制代码
本地广播和之前动态注册广播接收器以及发送广播的代码是差不多的,这里通过LocalBroadcastManager对象来发送广播和注册(取消注册)广播,并且其他程序的广播不会到本程序内部,本程序的广播也不会被其他的程序接收到.
此外本地广播是不能静态注册的,因为发送本地广播时我们的程序肯定已经启动了,而静态注册是为了即使程序在未启动的状态下也可以接收广播.