- Android移动应用开发实用教程
- 夏辉
- 3178字
- 2025-02-23 16:00:37
2.4 BroadcastReceiver
广播接收器(BroadcastReceiver)是Android系统的重要组件之一,用来接收来自系统和应用中的广播,是一种被广泛运用的、在应用程序之间传输信息的机制,是对发送出来的广播进行过滤接收并响应的一类组件。本节主要从3方面进行介绍:BroadcastReceiver简介、BroadcastReceiver生命周期和BroadcastReceiver实现机制。
2.4.1 BroadcastReceiver简介
在Android系统中,广播应用在很多方面,例如,当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作;当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度;时区的改变也会产生一条广播,接收到这条广播就能提醒用户改变时间设置;以及当处理应用或玩游戏时还可以接收短信等。
BroadcastReceiver用于接收广播Intent,广播Intent的发送是要把发送的信息和用于过滤的信息(如Action、Category)装入一个Intent对象,然后通过调用sendBroadcast()、sen-dOrderBroadcast()或sendStickyBroadcast()方法,把Intent对象以广播方式发送出去。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。
BroadcastReceiver自身并不实现图形用户界面,但是当它收到某个通知后,Broadcas-tReceiver可以启动Activity作为响应,或者通过NotificationMananger提醒用户,或者启动Service。
一个应用程序可有任意数量的广播接收器来响应它认为重要的任务通告。所有用户定义的广播接收器都继承于父类——BroadcastReceiver,其由Android平台框架预定义。
在Android系统中有以下3种广播类型。
●普通广播:发送一个广播,所有监听该广播的BroadcastReceiver都可以监听到该广播。
●异步广播:当由BroadcastReceiver处理完之后,Intent依然存在,此时registerReceiver(BroadcastReceiver,IntentFilter)还能收到它的值,直到把它去掉。
●有序广播:按照接收者的优先级顺序接收广播,优先级别在intent-filter中的priority中声明,-1000到1000之间,值越大,优先级越高。可以终止广播意图的继续传播。接收者可以篡改内容。
2.4.2 BroadcastReceiver生命周期
BroadcastReceiver的生命周期并不像Activity一样复杂,运行原理很简单,如图2-14所示。
每次广播到来时,会重新创建BroadcastReceiver对象,并且调用onReceive()方法,执行完以后,该对象即被销毁。Broad-castReceiver的生命周期只有10秒左右,当onReceive()方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver中不能做一些比较耗时的操作,否则会弹出ANR(Application No Response)的对话框。
图2-14 BroadcastReceiver生命周期
一个正在执行的BroadcastReceiver,即正在执行onReceive()方法的进程被认为是一个前台的进程,将会一直运行,除非系统处于内存可用容量极度低的情况。一旦从OnReceive()方法中返回,这个BroadcastReceiver对象就被系统认为应该结束了,将不会再被激活。如果进程仅仅只是拥有BroadcastReceiver,但并没有和它进行交互,此时一旦它从onReceive()方法中返回时,系统就会认为进程是空的,并且主动杀死它,以便这些资源可以被其他重要的进程利用。这意味着对于耗时的操作,可以采用将Service和BroadcastReceiver结合使用,以确保执行这个操作的进程在整个执行过程中都保持激活状态。
如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成。这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束而BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时BroadcastReceiver所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死,所以采用子线程来解决是不可靠的。
为了更好地理解BroadcastReceiver的生命周期,下面通过项目示例进行说明。
【例2-6】Example2-7 BroadcastReceiver示例。
1)新建工程Example2-7BroadcastReceiver,在工程的Src包中新建一个继承Broadcas-tReceiver的类MyBroadcastReceiver,主要实现onReceive()方法。主要代码如下。
【代码说明】
●第06行代码中参数为Intent.FLAG_ACTIVITY_NEW_TASK,表示区别于默认优先启动在activity栈中已经存在的activity(如果之前启动过,并且还没有被destroy),而无论是否存在,都需重新启动新的activity。
2)编辑MainActivity类,此Activity在AndroidMainfest.xml中被声明为对话框风格。在本例中,当Android系统所在时区被改变时,如图2-15a所示,会调用BroadcastReceiver对象中的onReceive()方法,在onReceive()方法中启动了本Activity,并可单击“确定”按钮退出本应用程序。运行效果如图2-15b所示。
图2-15 时区图
a)选择时区 b)更改时区
MainActivity的主要代码如下。
3)AndroidMainfest.xml中有关BroadcastReceiver组件的声明部分如下。
在AVD中运行该项目,然后操作改变系统时区,这时就会弹出提示框,可以单击“确定”按钮退出程序。如果此时再改变系统时区,就不会再弹出提示框了。说明在应用程序被安装之后,BroadcastReceiver始终处于活动状态,可以用于监听系统状态的改变。而一旦它从onReceive()方法中返回时,系统就会认为进程是空的,并且主动杀死它,以便这些资源可以被其他重要的进程利用。
2.4.3 BroadcastReceiver实现机制
当Intent发送以后,所有在系统中已经注册的BroadcastReceive会检查注册时的Intent-Filter是否与发送的Intent相匹配,若匹配则会调用BroadcastReceive的onReceive()方法。注册BroadcastReceiver有两种方式:静态注册和动态注册。
1.静态注册
如果要使监听器能够接收到广播所发送的Intent,就必须将这个BroadcastReceiver注册到系统当中,【例2-7】就属于静态注册方式。在AndroidMainfest.xml中注册文件的方法如下。
上述代码中,MyBroadcastReceiver是BroadcastReceiver的类名,android.intent.ac-tion.TIMEZONE_CHANGED是触发该BroadcastReceiver的Action的名称。能够触发BroadcastReceiver的Action有很多,具体可以查看Android的API文档。
2.动态注册
BroadcastReceiver被静态注册后,即使所在的应用程序没有启动,或者已经被关闭,这个BroadcastReceiver依然会继续运行,这样的运行机制可能会给软件的用户造成不便。所以作为程序的开发者,希望能够有一种灵活的机制完成BroadcastReceiver的绑定和解除绑定操作。Android当然也考虑到了这些问题,所以提供了以下两个函数。
●动态注册广播接收器:registerReceiver(BroadcastReceiver,Intentfilter),这个函数的作用就是将一个BroadcastReceiver注册到应用程序当中,这个函数接收两个参数,第一个参数是需要注册的BroadcastReceiver对象,第二个参数是一个IntentFilter。第一个参数是非常容易理解的,第二个参数的作用是定义了哪些Intent才能触发这个注册的BroadcastReceiver对象。类似于前面讲解的<intent-filter>标签的作用。
●解除动态广播接收器:unregisterReceiver(BroadcastReceiver),用于解除BroadcastRe-ceiver的绑定状态。一旦解除完成,响应的BroadcastReceiver就不会再接收系统所广播的Intent了。
为了更好地理解动态注册BroadcastReceiver的过程,参见下面项目示例。本示例通过一个自定义的静态注册广播接收器与动态注册广播接收器进行分析和比较。
【例2-7】Example2-7 dynamicBroadcastReceiver示例。
1)新建工程Example2-7dynamicBroadcastReceiver,在Src包中创建一个用于静态注册的广播接收器——StaticReceiver,主要代码如下。
2)在Src包中创建一个用于动态注册的广播接收器——dynamicReceiver,主要代码如下。
3)编辑MainActivity,用togglebutton按钮控件对动态广播接收器进行注册与解除注册。再分别用两个按钮实现发送给自定义的静态注册的广播接收器的Intent信息和发送给动态注册的广播接收器的Intent信息。主要代码如下。
【代码说明】
●第02行代码表示发送静态注册广播的按钮。
●第03行代码表示发送动态注册广播的按钮。
●第04行代码表示静态广播的Action字符串。
●第05行代码表示动态广播的Action字符串。
●第06行代码表示定义动态广播接收器对象。
●第10行代码表示获取Button按钮引用。
●第12行代码表示为Button按钮添加监听器。
●第1330行代码表示用ToggleButton对动态广播接收器进行注册与解除注册。
●第20行代码表示创建要动态注册的广播对象,此行必不可少。
●第21行代码表示创建Intent过滤器。
●第22行代码表示添加动态广播的Action。
●第23行代码表示注册自定义动态广播消息。
●第26行代码表示解除动态注册广播接收器。
●第3245行代码表示实现内部类OnClick监听器。
●第34行代码表示发送自定义静态注册广播消息。
●第37行代码表示添加附加信息。
●第38行代码表示发送Intent。
●第40行代码表示发送自定义动态注册广播消息。
4)AndroidMainfest.xml中有关静态注册BroadcastReceiver组件声明部分如下。
5)在AVD中运行项目,单击“发送静态注册广播”按钮,运行结果如图2-16a所示。然后单击“动态注册接收器”按钮,再单击“发送动态注册广播”按钮,运行结果如图2-16b所示。
通过本项目的运行结果,可以分析两种注册BroadcastReceiver方法的特点和各自的应用场合。
1)静态注册的方法可以保证在应用程序安装之后,BroadcastReceiver始终处于活动状态,通常用于监听系统状态的改变,例如手机的电量、Wi-Fi网卡的状态等。对于这样的BroadcastReceiver,通常是在产生某个特定的系统事件之后,进行相应的操作,例如Wi-Fi网卡打开时,给用户一个提示。
图2-16 广播接收器
a)静态广播接收器 b)动态广播接收器
2)动态注册方法相对静态注册要灵活很多,用此方法注册的BroadcastReceiver通常用于更新UI的状态。一般来说,都是在一个Activity启动时使用这样的方法注册BroadcastRe-ceiver,一旦接收到广播的事件,就可以在onReceive()方法中更新当前Activity中的控件。但是需要注意的是,如果这个Activity不可见了,就应该调用unregisterReceiver()方法来解除注册。