安卓四大组件之广播,安卓四大组件
广播是一种广泛运用的在应用程序之间传输信息的机制,Android 为了将系统运行时的各种“事件”通知给其他应用,因此内置了多种广播。广播机制最大的特点就是发送方并不关心接收方是否接到数据,也不关心接收方是如何处理数据的。Android 中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序的,前者是系统广播,后者是自定义广播。广播在具体的项目中应用场景并不多,但一旦使用会使得程序变得精简很多,因此本片文章就简单介绍一下安卓系统的广播机制。
首先,简单的介绍一下安卓的广播机制。BroadCastReceiver是对发送出来的Broadcast 进行过滤接受并响应的一类组件,是Android四大组件之一,主要用于接收系统或者app发送的广播事件。在我们的项目中经常使用广播接收者接收系统通知,比如开机启动、sd挂载、低电量、外播电话、锁屏等。 如果我们做的是播放器,那么监听到用户锁屏后我们应该将我们的播放之暂停等。android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系, 有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。广播有利于程序间互通消息,例如在自己的应用程序内监听系统来电。
BroadCastReceiver的一般编写步骤:
1. 写一个类继承BroadCastReceiver;
2. 重写oncreat()方法;
3. 注册广播。动态注册和静态注册,前者在java代码中实现,后这在清单文件中编写。动态注册需要写BroadCastReceiver的实现类和过滤器,静态注册除了写过滤器外还要在receiver标签的name属性上添加包名和类名。
按照广播的属性来分,广播分两种:有序广播和无序广播。
无序广播:又叫普通广播,完全异步,不会被某个广播接收者终止,逻辑上可以被任何广播接收者接收到,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。优点是效率较高。缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播intent的传播。Context.sendBroadcast() 发送的是普通广播,所有订阅者都有机会获得并进行处理。
有序广播:按照被接收者的优先级顺序,在被接收者中依次传播。比如有三个广播接收者A,B,C,优先级是A > B > C。那这个消息先传给A,再传给B,最后传给C。,因此通常需要在AndroidManifest.xml 中进行注册,优先级别声明在intent-filter 元素的android:priority 属性中,数越大优先级别越高,取值范围:-1000 到1000,优先级别也可以调用IntentFilter 对象的setPriority()进行设置。有序广播的接收者可以终止广播的传播,广播的传播一旦终止,后面的接收者就无法接收到广播,有序广播的接收者可以将数据传递给下一个接收者,如:A 得到广播后,可以往它的结果对象中存入数据,当广播传给B 时,B 可以从A 的结果对象中得到A 存入的数据。Context.sendOrderedBroadcast() 发送的是有序广播。Bundlebundle = getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。
对于有序广播有一个小细节,那就是优先级高的广播可以终结一个广播。终止一个有序广播:abortBroadcast()。终止有序广播只需要一句代码,该代码是BroadCastReceiver 类中的方法,因此这里可以直接使用。这里需要注意的是如果abortBroadCast 是在一个无序广播中执行的,那么就会报如下异常:
java.lang.RuntimeException:
BroadcastReceiver trying to return result during a non-ordered broadcast
在低版本的手机上比如Android2.3 上是不会报这样的异常的,安卓工程师认为终止无序广播是不合法的操作,因此在Android2.3之后的版本,终止无序广播都是非法操作。为了防止我们终止一个无序广播导致报异常,我们可以先判断接收到的广播类型。优化后的代码如下:
if (isOrderedBroadcast()) {
abortBroadcast();
}
isOrderedBroadcast 方法是BroadCastReceiver 类提供的,用于判断当前的广播类型。返回true 为有序广播,返回false 为无序广播。
之后,再来讲一下广播的注册机制。广播注册方式有两种,动态注册和静态注册。在清单文件中注册广播接收者称为静态注册,在代码中注册称为动态注册。静态注册的广播接收者只要app在系统中运行则一直可以接收到广播消息,动态注册的广播接收者当注册的Activity或者Service销毁了那么就接收不到广播了。
静态注册:在清单文件中进行如下配置
<receiver android:name="包名+类名" > <intent-filter> <action android:name="android.intent.action.CALL" > </action> </intent-filter> </receiver>
动态注册:在代码中进行如下注册
//广播发送者: Intent intent = new Intent(); intent.setAction(Uri); intent.putExtra("packname", packname); sendBroadcast(intent); //自定义广播接受中: receiver = new BroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Uri); context.registerReceiver(receiver, intentFilter);
按照广播的编写方式来分,又可以分为系统广播和自定义广播两种。
系统广播的应用较为普遍,比如文章开头所讲的:系统电量的改变、屏幕的锁屏、网络状态的改变、接收到新的短信、拨打电话事件、sdcard 的挂载和移除、应用的安装和卸载等等。比如我们开发的在线播放视频类的APP,那么我们就有必要监听网络转态改变的事件广播,如果用户的网络状态从wifi 改变为了4G 上网,那么应该提示用户是否使用4G 网络继续播放视频,如果不提示用户,那么就可能导致用户流量被大量使用,一会儿功夫,用户可能就要停机了。这些都是通过系统广播完成。Android给许多系统服务广播Intent。你可以使用这些基于系统事件的消息来给自己的工程增添一些功能,这些事件如时区变更、数据连接状态、SMS消息或电话呼叫。系统广播的编写也较为简单,通过查看底层源码获取相关的action节点及其他参数,然后把这些写在清单文件中或动态写在java代码中,就可以在BroadCastReceiver的实现类中接受广播了。文章最后给出一个屏幕点亮和熄灭的案例,再次就不在赘述。
给出几种常用的系统广播监听事件中清单文件的写法。当然若是动态注册,只需要在java代码中添加过滤器即可,节点参数类似。
<--!监听SD卡状态的receiver节点:--> <receiver android:name="包名+类名" > <intent-filter> <action android:name="android.intent.action.MEDIA_UNMOUNTED"/> <data android:scheme="file"></data>