7.3.2 BroadcastReceiver组件
图7-34 界面切换图
本节介绍Android4大组件之一的BroadcastReceiver。先了解以下一些必要的概念。
1)Broadcast(广播) 是一种广泛运用在应用程序之间用来传输信息的一种机制。
2)BroadcastReceiver(广播接收者) 是对发送出来的广播进行过滤接收并响应的一类组件,它的作用就是用来接收来自系统或者应用中的广播。
实际中,广播及广播接收者的用途很多,例如当手机开机完成后,系统会产生一条广播。一些开机启动的程序,一旦接收了这条广播,都会自动启动,从而实现了一些开机自启动的功能;当网络状态改变时,系统也会产生一条广播,当收到这条广播后,就可以对程序进行保存数据或者其他相应的处理。
注意:BroadcastReceiver的生命周期只有10s左右,因此在BroadcastReceiver里不能做一些比较耗时的操作;不能使用子线程。
1.介绍广播的使用方法
1)发送:将信息装入一个Intent对象(如Action、Category),通过调用相应的方法sendBro-dacast()、sendOrderBrodacast()或sendStickyBrodacast(),将Intent对象以广播的方式发送出去。
2)接收:当Intent发送出去以后,所有已经注册的BroadcastReceiver会检查注册时的Intent-Filter是否与发送的Intent相匹配。一旦匹配,就会调用类BroadcastReceiver中的onReceive()方法。
例如,先准定义一个按钮准备用来发送广播:
2.介绍接收广播和发送广播
(1)接收广播
在onReceive方法内,可以获取随广播传送过来的Intent中的数据,就像无线电一样,包含很多有用的信息。下面先创建一个名为MyReceiver广播接收者:
在创建自己的BroadcastReceiver对象时,需要继承android.content.BroadcastReceiver,并实现其onReceive方法,可以通过以上程序实现。在创建BroadcastReceiver之后,并不能够使它马上进入工作状态,原因在于还需要为它注册一个指定的广播地址。值得注意的是,注册广播地址可分为静态注册和代码注册(也称动态注册)。
1)静态注册。静态注册是在AndroidManifest.xml文件中配置的。为MyReceiver注册一个广播地址:
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
注册完成后,只要是android.intent.action.MY_BROADCAST这个地址的广播,MyReceiver都可以接收到。并且,这种方式的注册是常驻型的,即当应用关闭后,如果有广播信息传来,MyReceiver也会被系统调用而自动运行。
2)代码注册:代码注册需要在代码中动态的指定广播地址并注册,通常是在Activity或Service注册一个广播。下面就来看一下注册的代码:
Activity和Service都继承了ContextWrapper,而registerReceiver是android.content.Context-Wrapper类中的方法,所以可以直接进行调用。
在Activity或Service中使用代码注册BroadcastReceiver时,需要注意的是当Activity或Serv-ice被销毁时要进行解除注册。如果没有解除注册,通常系统会提示一个异常,所以要记得在组件结束的地方进行解除注册操作,代码如下:
这种注册方式与静态注册不同,不是常驻型的,这样注册的广播会跟随程序的结束而结束。
最后,单击发送按钮,执行send方法,控制台打印如下:
(2)发送广播
广播接收器接收系统广播后,如何在应用程序中发送广播?广播主要分为两种类型:标准广播(又称无序广播)和有序广播,下面将通过实践的方式区别这两种广播。
1)标准广播的特点 同级别接收时间是随机的;级别低的迟一点收到广播;接收器不能截断广播的继续传播,也不能对广播进行处理;同级别的动态注册高于静态注册。
对于标准广播来说,最大的特点就是接收器不能截断广播的继续传播,同时也不能对广播进行处理。下面简单地验证一下。我们新建3个BroadcastReceiver,演示这个过程,FirstReceiver、SecondReceiver和ThirdReceiver。具体代码如下:
①FirstReceiver代码
②SecondReceiver代码
③ThirdReceiver代码
然后像之前单击发送按钮,系统会发送一条广播,控制台打印如下:
可以清楚的看到3个都接收到这条广播,接下来对代码进行略微的修改,试图终止广播。我们在onReceive方法的最后一行添加以下代码:
abortBroadcast();
最后,单击一下发送,再次观察控制台的信息:
控制台依然打印了三个接收器的日志,可以发现接收者并不能终止广播。
2)有序广播的特点。同级别接收顺序也是随机的;能截断广播的继续传播,高级别的接收器接收到广播后,可以控制该广播继续传播或者是将之截断;接收器能处理广播;同级别的动态注册高于静态注册。
对于有序广播来说,每次只发送给优先级高的接收器,然后再由优先级高的接收器选择传播到低优先级的接收器。
用实验的方法来理解这个过程。同样,先新建3个BroadcastReceiver,分别为FirstReceiver、SecondReceiver和ThirdReceiver。
①FirstReceiver代码
②SecondReceiver代码
③ThirdReceiver代码
在FirstReceiver和SecondReceiver中最后都使用了setResultExtras方法,将一个Bundle对象设置为结果集对象,传递到下一个接收者,这样优先级低的接收者可以用getResultExtras获取到最新的经过处理的信息集合。
接着,需要为这3个接收器注册广播地址,修改AndroidMainfest.xml文件:
<receiverandroid:name=".FirstReceiver">
<intent-filterandroid:priority="300">
<actionandroid:name="android.intent.action.MY_BROADCAST"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<receiverandroid:name=".SecondReceiver">
<intent-filterandroid:priority="200">
<actionandroid:name="android.intent.action.MY_BROADCAST"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<receiverandroid:name=".ThirdReceiver">
<intent-filterandroid:priority="100">
<actionandroid:name="android.intent.action.MY_BROADCAST"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
通过AndroidMainfest.xml文件,可以发现FirstReceiver中的android:priority为300,Secon-dReceiver的为200,ThirdReceiver的为100。这个android:priority属性的范围:-1000到1000,数值越大,表示优先级越高。所以不难发现FirstReceiver的优先级高于SecondReceiver高于Thir-dReceiver。
然后,还需要修改发送广播的代码:
这段代码中使用了sendOrderedBroadcast方法发送有序广播时,需要一个权限参数。接收者若要接收此广播,需声明指定权限。
在AndroidMainfest.xml中定义一个权限:
<permissionandroid:protectionLevel="normal"
android:name="scott.permission.MY_BROADCAST_PERMISSION"/>
然后声明使用了此权限:
<uses-permissionandroid:name="scott.permission.MY_BROADCAST_PER-MISSION"/>
接着,我们单击发送按钮发送一条广播。控制台打印如下:
从控制台中,可以看到接收器接收是按顺序的,并且由高优先级向低优先级传递。通过实验再来看看高优先级能不能阻断广播的传播。打开FirstReceiver的代码,在onReceive的最后一行添加以下代码来试图阻止广播的传播:
abortBroadcast();
发送广播后,控制台打印如下:
这时,发现只有FirstReceiver接收到广播,其他两个接收器都没有执行,因为广播被FirstReceiver终止了。