- 什么是BroadcastReceiver
BroadcastReceiver是安卓中的四大组件之一。
广播接收器,也被称为全局事件,或系统事件。
当Android系统中任何程序有动作时,如果想通知其他程序,采用广播的方式进行传播是非常有效的。广播从理论上说,可以将一个动作传播给任意多个程序(当然,广播接收器的数量会受到系统限制)。
在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理。这个广播跟我们传统意义中的电台广播有些相似之处。之所以叫做广播,就是因为它只负责“说”而不管你“听不听”,也就是不管你接收方如何处理。另外,广播可以被不只一个应用程序所接收,当然也可能不被任何应用程序所接收。
广播机制最大的特点就是发送方并不关心接收方是否接到数据,也不关心接收方是如何处理数据的。
Android中广播的是操作系统中产生的各种各样的事件。例如,收到一条短信就会产生一个收到短信息的事件。而Android操作系统一旦内部产生了这些事件,就会向所有的广播接收器对象来广播这些事件。
广播机制的三要素:
Android广播机制包含三个基本要素:
1、广播(Broadcast) - 用于发送广播;
2、广播接收器(BroadcastReceiver) - 用于接收广播;
3、意图内容(Intent)-用于保存广播相关信息的媒介。
Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的Broadcast进行过滤接受并响应的一类组件。、
广播的生命周期:
1、广播接收器仅在它执行这个方法时处于活跃状态。当onReceive()返回后,它即为失活状态。
2、拥有一个活跃状态的广播接收器的进程被保护起来而不会被杀死,但仅拥有失活状态组件的进程则会在其它进程需要它所占有的内存的时候随时被杀掉。
3、如果响应一个广播信息需要很长的一段时间,一般会将其纳入一个衍生的线程中去完成,而不是在主线程内完成它,从而保证用户交互过程的流畅。广播接收程序的时间限制为10秒。
- Android中广播分类
Android中广播主要分为2类:标准广播和有序广播
- 标准广播:标准广播(Normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
2、有序广播(Ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了,甚至前面的广播可以修改广播内容再传递给下一个广播。
- 如何使用BroadcastReceiver
- 定义一个类来继承系统提供的BroadcastReceiver类。然后覆写其中的方法:
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
}
该方法内部写接收到广播之后的逻辑处理代码。
注意:1、此方法是在UI线程中执行的,所以不能执行耗时操作。2、数据都封装在intent对象中,可以从此对象中取出需要的数据如果需要执行耗时操作,则可以启动子线程来执行。
- 由于BroadcastReceiver是四大组件之一,所以需要在AndroidManifest文件中注册BroadcastReceiver(静态注册)。
<receiver android:name=".IncomingSMSReceiver"> //自定义广播接受者
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
注意:1、广播接收者的类名建议使用全名(包名.类名)2、意图过滤器中action是指的当前action能接受的广播类型。3、可以注册的时候给意图过滤器添加属性android:priority="100"来说明该广播的优先级。当接受有序广播时,优先级越高越先收到广播。
3.BroadcastReceiver是四大组件中唯一支持使用java代码进行注册的组件(动态注册),所以第二步中的在AndroidManifest文件中的注册也可以使用java代码注册来替换。
public class MainActivity extends Activity {
private IntentFilter intentFilter;
private MyReceiver myReceiver;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建意图过滤器对象
intentFilter = new IntentFilter();
//给创建的意图过滤器对象指定action动作,来指明将来的广播接受者接收广播的类型
intentFilter.addAction("com.qianfeng.aaa");
//创建广播接收对象
myReceiver = new MyReceiver();
//使用代码动态注册广播接收。参数一:广播接受者 参数二:意图过滤器
registerReceiver(myReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//当Activity销毁的时候,取消广播接收的注册。
unregisterReceiver(myReceiver);
}
}
注意:1、静态注册的广播接收者app一旦安装在系统,则可以接收到指定的广播。不管这个app有没有启动。 2、动态注册的广播接收者只有在注册完成后才能接收到广播,当注册他的组件销毁的时候,广播接收者也应该解除注册。
- 发送广播
广播的发送和接收是跨进程的,一个app发送的广播,其他的app只要权限和action匹配都可以接收到该广播
- 发送标准广播
//创建意图对象,并指明action,那么意图过滤器与这个action匹配的广播接受者会
//接收到这个广播
Intent intent = new Intent("com.qianfeng.MY_BROADCAST");
//发送出去广播
sendBroadcast(intent);
注:发送广播的方法都是上下文对象中的方法。
- 发送有序广播
Intent intent = new Intent("com.qianfeng.MY_BROADCAST");
//发送有序广播。 参数一:意图对象 参数二:权限。是否需要接受者需要选取才可//以收到广播
sendOrderedBroadcast(intent, null);
或者:
//由于发送有序广播的时候,中间会有可能被拦截掉,参数三则指定了一个这个广播
//的最终接受者,也就说即使中间有人拦截了广播,则参数三指定的接
//受者也会最终接收到这个广播。
//其余的参数给null或0即可
sendOrderedBroadcast(it, null, receiver, null, 0, null, null);
/*
*参数一:意图对象,发送什么样的广播
* 参数二:权限 一般不需要
* 参数三:是最后一个收到广播的接受者,他可以不用注册,也能收到
* 参数四:指明最终的接受者执行的线程(如果Handler对象时在子线程创建则handMessage方法是在子线程执行)。传null,怎默认是在主线程执行
* 参数五:初始化的code
* 参数六:初始化的数据
* 参数七:传递比较复杂的数据可以使用Bundle对象
*
* 最终的接收者收到的数据是有可能被中间的接收者篡改
*/
注意:
1、发送有序广播的时候,先接到广播的可以通过下面的方法来取消广播,导致后面的优先级低的广播接收者收不到广播。
abortBroadcast(); //放弃当前的广播,则优先级低的无法收到当前广播
2、如果优先级高的广播接收者想给优先级低的广播接收者传递数据可以通过下面的方法:
setResult()
setResultData()
setResultCode()
setResultExtra()
对方用getResultData()获得数据
- 使用LocalBroadcastManager
LocalBroadcastManager是Android Support包提供了一个工具,是用来在同一个应用内的不同组件间发送Broadcast的。
使用LocalBroadcastManager有如下好处:
发送的广播只会在自己App内传播,不会泄露给其他App,确保隐私数据不会泄露
其他App也无法向你的App发送该广播,不用担心其他App会来搞破坏
比系统全局广播更加高效
和系统广播使用方式类似:
先通过LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); 获取实例
然后通过函数 registerReceiver来注册监听器
lbm.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Handle the received local broadcast
}
}, new IntentFilter(LOCAL_ACTION));
通过 sendBroadcast 函数来发送广播
lbm.sendBroadcast(new Intent(LOCAL_ACTION));
- 广播接收案例(接收一些系统广播)
系统在合适的时间发送广播,我们的app通过接收这些广播可以实现一些比较实用的功能。如:系统启动完成、用户外拨电话、短信来到等等,系统都会发出相应的广播。
ACTION_TIME_CHANGED :系统时间被改变;
ACTION_DATE_CHANGED : 系统日期被改变;
ACTION_TIMEZONE_CHANGED :系统时区被改变;
ACTION_BOOT_COMPLETED :系统启动完成;
ACTION_BATTERY_CHANGED : 电池电量改变;
ACTION_SHUTDOWN : 系统被关闭;
Action_BATTRY_LOW : 电池电量低;
- 软件自启动
通过监听系统启动完成这个广播,可以实现软件的自启动的功能。
- 定义广播接收者。注册广播接收者的意图过滤器添加action为:android.intent.action.BOOT_COMPLETED
- 添加权限:<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
- 在广播接收者的OnReceive()方法中来启动相应的组件,来达到软件自启动的目的。
Intent需要添加标记Intent.FLAG_ACTIVITY_NEW_TASK
- 拦截外拨电话
- 定义广播接收者。注册
<intent-filter android:priority="66666">
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
2、添加权限<!-- 接收外拨电话的广播的权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<!-- 接收开机广播 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
3、在广播接收者的OnReceive()方法
String number = getResultData();
if (number.startsWith("186000")) {
//Toast.makeText(context, "有电话拨出" + number, 1).show(); // getResultData()
abortBroadcast(); // 放弃这个广播. 对外拨电话的,已经制定了最终的接收者。拦不了。
setResultData("");
}
- 短信拦截
- 注册广播接收者
<receiver
android:name="com.example.day17_01_broadcast_sms.MyBroadacast" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
2.读写短信的权限:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
3.处理接收到的短信:
- 网络、Wifi状态的访问
Android网络应用程序开发中,经常要判断网络连接是否可用,因此经常有必要监听网络状态的变化。
- 注册:意图过滤器的action
< action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
- 权限:
< uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
- 代码:
获得电量信息
public class MainActivity extends Activity {
private ProgressBar bar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bar = (ProgressBar) findViewById(R.id.bar);
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
MyReceiver receiver = new MyReceiver();
this.registerReceiver(receiver, filter);
}
class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
int current = intent.getExtras().getInt("level");
int count = intent.getExtras().getInt("scale");
bar.setMax(count);
bar.setProgress(current);
}
}
}
系统的Broadcast Action:
android.intent.action.BATTERY_CHANGED
充电状态,或者电池的电量发生变化
android.intent.action.BOOT_COMPLETED
在系统启动后,这个动作被广播一次(只有一次)
android.intent.action.CFF
语音电话的呼叫转移状态已经改变
android.intent.action.CONFIGURATION_CHANGED
设备的配置信息已经改变,参见 Resources.Configuration
android.intent.action.DATA_ACTIVITY
电话的数据活动(data activity)状态(即收发数据的状态)已经改变
android.intent.action.DATA_STATE
电话的数据连接状态已经改变
android.intent.action.DATE_CHANGED
日期被改变