Android开发笔记(六)- BroadcastReceiver组件
在介绍了Activity组件和Service组件之后,这篇文章将会介绍Android开发中的第三个重要组件:BroadcastRecevier。简单来说,BroadcastReceiver
主要用于监听、接收来自Android系统或者其他应用程序的广播信息,是用于不同APP之间,以及APP和Android系统之间通信的重要工具。APP可以根据接收到的信息,采取不同的操作来进行响应。
BroadcastReceiver
首先还是先上Google的官方说明文档:
Android apps can send or receive broadcast messages from the Android system and other Android apps, similar to the publish-subscribe design pattern. These broadcasts are sent when an event of interest occurs.
这里值得注意的是:BroadcastReceiver
使用了观察者模式(Observer Pattern),从而解耦了广播的发送者和接收者。一个APP既可以是广播的发送者,也可以是接收者。发送广播需要通过手动调用sendBroadCast(Intent)
方法来完成,而接收广播则需要通过注册一个自定义的BroadcastReceiver子类来完成。
实现原理
BroadcastReceiver
的工作流程如下图所示:
如上图所示,其中实现BroadcastReceiver子类以及注册子类需要通过代码手动完成,其他部分均是自动完成的。那么我们就来看看如何创建并注册BroadcastReceiver子类,示例代码如下:
1 | class SampleBroadcastReceiver: BroadcastReceiver() { |
要注意的是:一般情况下onReceive()
会运行在主线程(main thread),所以为了避免ANR,尽量不要在这里执行长时间的复杂操作,必要的话可以从这里开启一个Service来执行具体的操作。
静态注册 VS 动态注册 (重要!!!)
实现了BroadcastReceiver子类之后,就是要在消息中心进行注册(register),这里可以采用两种注册方式:静态注册和动态注册:
静态注册(静态广播)
在Androidmanifest.xml
中对实现的BroadcastReceiver子类进行声明,示例代码如下:
1 | <receiver |
其中receiver
标签内可以定义注册时的很多属性,比如exported
,enabled
,permission
,precess
等,而intent-filter
标签里则定义了允许接收的广播类型,比如BOOT_COMPLETED
就是当Android设备Boot结束时系统会发送的广播类型,而INPUT_METHOD_CHANGED
则是当用户切换了输入法时系统会发送的广播类型。通过在intent-filter
里声明各种不同的广播类型,可以让APP对于不同的系统事件做出反应(onReceive()
被调用)。
动态注册(动态广播)
在代码中手动调用Context.registerReceiver()
方法,传入BroadcastReceiver
子类实例,并在使用结束后手动调用unregisterReceiver()
方法来销毁。在Activity中使用动态注册的实例代码如下:
1 | class BroadcastDemoActivity : AppCompatActivity() { |
两者区别
- 使用静态注册时,当app退出后,BroadcastReceiver依旧可以接收广播并处理,而使用动态注册时,BroadcastReceiver的生命周期跟随Context的生命周期。例如,如果使用
Activity.registerReceiver()
,则当activity销毁时,receiver也会失效;而使用ApplicationContext.registerReceiver()
时,当application退出时,receiver才会失效; - 使用静态注册时,不需要手动声明销毁;而使用静态注册时,需要通过手动调用
unregisterReceiver()
来销毁接收器对象,否则会出现内存泄漏的情况,一般来说要在activity的onResume()
和onPause()
中成对出现,因为其他的生命周期都无法保证被成对调用,会出现重复注册或无法销毁的情况,Activity的生命周期相关内容可以看这里; - 静态注册会更消耗内存和设备的电量,常用于需要时刻监听广播的情况,而动态注册更加灵活,常用于特定情况需要监听广播的情况,一般来说动态注册要优于静态注册。
Broadcast广播类型
普通广播(normal broadcast)
通过发送、接收包含自定义Action的Intent来实现通信的广播,这个Intent可以是开发者自行定义并创建的,普通广播是最常用的广播类型。如果发送的广播包含权限,那么接收器也需要相对应的权限才能接收。示例代码如下:
1 | // 创建一个Intent示例并设置自定义的Action |
此时,只需要广播接收者在注册时添加这个my_custom_action_name
作为监听的广播类型(Action)即可接收这个自定义的广播。要注意的是,普通广播不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播。
系统广播(system broadcast)
Android系统内置的广播,Android操作系统是发送者,主要用于监听手机的操作,状态变化等信息。不需要手动发送广播,只需要注册特定Action类型的接收器就可以等待接收。常用的系统广播包括:ACTION_AIRPLANE_MODE_CHANGED()
,ACTION_BATTERY_LOW
,ACTION_BOOT_COMPLETED
等,系统广播的所有Action类型可以在这里找到。
本地广播(local broadcast)
普通广播意味着其他APP也可以发送、接收当前APP的广播,但如果想获得效率更高,安全性更强的广播,可以使用本地广播。可以把它理解成一种APP内部的局部广播,它可以通过不同的方式来阻止外部广播的发送和接收。具体的方式有两种:
- 对普通广播加以限制,使其只能在APP内部通信:
- 对于静态注册的BroadcastReceiver,可以通过在
manifest.xml
中加入exported = "false"
,使得非App内部发出的此广播不被接收。并且增设相应权限permission
,用于权限验证; - 对于动态注册的BroadcastReceiver,可以通过调用
intent.setPackage(packageName)
来指定目标广播接收器的包名,可以使除此包名外的所有接收器无法接受广播(排他性);
- 对于静态注册的BroadcastReceiver,可以通过在
- 使用
LocalBroadcastManager
类来进行动态注册,此时发送、接受的广播全部属于本地广播,但是LocalBroadcastManager已经被弃用了,所以这里就不多做解释了。
有序广播(ordered broadcast)
不论是普通广播,还是系统广播,都是按照随机顺序发送给所有符合条件的接收者的。但是有序广播会按照priority
由大到小的顺序,依次发给所有符合条件的接收者。priority在manifest.xml
或者通过手动调用intentFilter.setPrority(1000)
来设置,prority是一个Int类型,示例代码如下:
1 | // 静态注册设置prority |
这里要注意有序广播区别于其他广播的几个特点:
- 有序广播可以被截止,高优先级(priority)的广播接收者有权利决定比它低的接收者们是否可以接收到对应的广播,截断广播通过手动调用
abortBroadcast()
来实现; - 有序广播可以被修改,高优先级(priority)的广播接收者可以修改后续比它低的接收者们所接收到的广播;
- 有序广播可以设置终结接收者,也就是无论终结接收者的优先级,最终它都会接收到广播并在此终结。
滞留广播(sticky broadcast)
滞留广播在发送后会一直等待,在有符合条件的接收器被注册后,会立刻发送至该接收器,并继续等待。发送滞留广播需要获得BROADCAST_STICKY
权限,而停止滞留广播需要手动调用removeStickyBroadcast()
方法。因为滞留广播也已经在API 21中弃用,这里就不再多讲了。
注意事项
对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回类型是不一样的:
- 对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回类型是ReceiverRestrictedContext;
- 对于全局广播的动态注册,回调onReceive(context, intent)中的context返回类型是Activity Context**;
- 对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回类型是Activity Context;
- 对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回类型是Application Context。
参考文章
Google Document: BroadcastReceiver overview
Android四大组件:BroadcastReceiver史上最全面解析
Android四大组件——BroadcastReceiver普通广播、有序广播、拦截广播、本地广播、Sticky广播、系统广播