Android有四大组件,分别为:Activity(活动)、Service(服务)、Content Provider(内容提供器)、Broadcast Receiver(广播接收者)。
引入广播的目的是便于接收和发送系统级(而不只是应用内部)的通知,使得Android的任意一个应用可以接收来自于系统和其他应用的消息。其机制类似于设计模式中的观察者模式(或发布-订阅模式)。
广播的Android官方文档:Broadcasts
全局广播
因为下面还会介绍一种本地广播,因此将这部分称为全局广播。“全局”体现在所有应用都可以接收到广播,只要这些应用有注册接收者。
两种广播类型
-
标准广播
标准广播是我们通常意义上所理解的广播,即一旦发送广播,在广播范围内的接收者都能同时收到广播。
-
有序广播
“有序”指的是接收者排队按顺序接收广播,就像传纸条游戏一样。这种类型非常重要的一点是先接收广播的接收者可以决定是否将广播继续传递下去。
广播的发送者
-
Android系统
系统广播包括但不限于:网络状态(7.0系统不推荐使用广播来接收)、开关机状态、电量状态。
-
某个应用
通常是自定义的广播
广播接收者
广播接收者必须继承BroadcastReceiver这个类。BroadcastReceiver是一个抽象类,它做了很多实现,但留下一个抽象方法给程序员去实现。
public abstract void onReceive(Context context, Intent intent);
继承BroadcastReceiver之后只需实现这个方法。在里面写上接收到所期望的广播时的处理代码就行了。需要注意的是,不能在这里面做耗时的处理。一旦超过10秒还没return,程序就会报错。如果想做耗时处理,可以开启后台服务。
在onReceive里开启线程之前需要执行goAsync()获取PendingResult,以此告诉系统当onReceive()执行结束之后,需要一些时间来完成线程的任务。在线程里面需要调用PendingResult的finish()来告诉系统线程已经完成任务。
两种广播接收者注册方式
在广播接收者的代码中没有声明响应哪些广播,因此需要在其他地方注册。
-
代码中基于Context的动态注册
由于Context有Activity级和Application级的,因此这两种方式的广播有效时期不一样。Activity级的广播接收者会在Activity的onDestroy()执行之后变为无效,而Application级的广播接收者只要APP还在运行,它就有效。
当使用Context的广播接收者时,需要调用registerReceiver(BroadcastReceiver, IntentFilter) 和 unregisterReceiver(BroadcastReceiver)来注册和注销。这两个方法都在Context类里面。如果想注册Application级别的,就需要getApplicationContext()。在注册时传入IntentFilter用于指定期望接收的广播。
-
AndroidManifest.xml的静态注册
Android系统的包管理器(package manager)会在APP安装到手机的时候注册写在这里的广播接收者。一旦注册,这个广播接收者成为指向该APP的一个独立个体。这样就意味着即使APP没有在运行,这个广播仍然可以正常运作。
广播接收者需要写在application标签内,它的标签是receiver,需要指定name和intent-filter。举个例子:
<application ...> ... <receiver android:name=".MyBroadcastReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> </application>
选择哪种注册方式主要看需求。如果想要在程序没有启动的情况下就响应广播,那么就采用静态注册;如果只想在程序启动的情况下接收广播,就用动态注册。
无论是用哪种方式注册广播,其广播接收器的写法都是一样的。
自定义广播
自定义广播的关键是Action的定义。
Intent intent = new Intent("com.example.yourappname.YOUR_BROADCAST_NAME");
sendBroadcast(intent);
需要注意的是,自定义的Intent Action是一个字符串,这个字符串你可以按照以上的格式写。
在写接收者的Action时,把上面定义的字符串作为Action复制过去就行了。
发送有序广播
将sendBroadcast(intent);
改为 sendOrderedBroadcast(intent, null)
就行了。第二个参数是权限相关的字符串,如果没有权限要求,就填null。
-
如何决定广播的顺序?
intent filter有一个priority的参数,设置得越高就越先接收。
-
如何截断广播?
在BroadcastReceiver的onReceive中调用abortBroadcast()就行了。如果你想在某种情况下截断广播,则需要判断语句。
-
前面的接收者和后面的接收者之间沟通
通过在onReceive()中执行setResultData()来设置给后面接收者的内容,执行getResultData()来获取前面接收者设置的内容。
本地广播
某些广播的目的地是应用内部,它们可能含有关键性的数据。为了防止这些广播被其他程序获取,引入了LocalBroadcastManager(本地广播)。
本地广播和全局广播的不同之处主要有以下几点:
- 不能在AndroidManifest.xml里注册receiver
- 需要获取LocalBroadcastManager实例
- 发送广播时要用LocalBroadcastManager实例调用sendBroadcast(Intent intent)
广播接收者的写法是一样的。