天天看点

Android组件系列----BroadcastReceiver广播接收器

【正文】

一、广播的功能和特征

广播的生命周期很短,经过调用对象-->实现onreceive-->结束,整个过程就结束了。从实现的复杂度和代码量来看,广播无疑是最迷你的android 组件,实现往往只需几行代码。广播对象被构造出来后通常只执行broadcastreceiver.onreceive方法,便结束了其生命周期。所以有的时候我们可以把它当做函数看也未必不可。

和所有组件一样,广播对象也是在应用进程的主线程中被构造,所以广播对象的执行必须是要同步且快速的。也不推荐在里面开子线程,因为往往线程还未结束,广播对象就已经执行完毕被系统销毁。如果需要完成一项比较耗时的工作 , 应该通过发送 intent 给 service, 由 service 来完成。

每次广播到来时 , 会重新创建 broadcastreceiver 对象 , 并且调用 onreceive() 方法 , 执行完以后 , 该对象即被销毁 . 当 onreceive() 方法在 10 秒内没有执行完毕, android 会认为该程序无响应。

二、接收系统广播:

广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广播接收器就能收到该广播,并在内部处理相应的逻辑。注册广播的方式有两种,在代码中注册和在清单文件中注册,前者称为动态注册,后者称为静态注册。

1、动态注册监听网络变化:

新建工程文件,首先在mainactivity中定义一个内部类networkchangereceiver,并重写父类的onreceive()方法,这样每当网络状态发生变化时,onreceive()方法就会得到执行,这里使用toast提示一段文本信息,代码如下:

紧接着在oncreate方法中进行动态注册,然后在ondestroy方法中进行取消注册:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

上方代码解释如下:

11行:给意图过滤器intentfilter添加一个值为android.net.conn.connectivity_change的action。因为每当网络状态发生变化时,系统就会发出一条值为android.net.conn.connectivity_chang的广播。

注:最后要记得,动态注册的广播接收器一定要取消注册才行。

运行程序,就可以了。

不过只是提醒网络发生变化还不够人性化,为了能够准确的告诉用户当前是有网络还是没有网络,我们还需要对上述代码进一步优化,修改networkchangereceiver中的代码如下:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

上方代码解释:

06行:在onreceive()方法中,首先通过通过getsystemservice()方法得到connectionmanager这个系统服务类,专门用于管理网络连接。

07行:然后调用它的getactivenetworkinfo()方法可以得到networkinfo的实例,接着调用networkinfo的isavailable()方法,就可以判断当前是否有网络了,最后通过toast提示用户。

另外,查询系统的网络状态是需要申明权限的,打开清单文件,添加如下权限:

现在运行程序,就可以了。

上方程序完整版代码如下:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

2、静态注册实现开机启动:

动态注册的方式比较灵活,但缺点是:必须在程序启动之后才能接收到广播,因为注册的逻辑是写在oncreate()方法中的。为了让程序在未启动的情况下就能接收到广播,这里就需要使用到静态注册。

这里我们准备让程序接收一条开机广播,当收到这条广播时,就可以在onreceive()方法中执行相应的逻辑,从而实现开机启动的功能。

新建一个类:bootcompletereceiver,让他继承broadcastreceiver,在onreceive()方法中简单地toast一下,代码如下:

可以看到,这里不再使用内部类的方式来定义广播接收器,因为稍后我们需要在清单文件androidmanifest.xml中将这个广播接收器的类名注册进去。

然后修改清单文件androidmanifest.xml,代码如下:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

代码解释如下:

终于,<application>标签内多了个子标签<receiver>,所有的静态注册的广播接收器都是在这里进行注册的。

22行:name中为广播接收器的名字

24行:想要接收的广播。android系统启动完成后,会发出这条名为android.intent.action.boot_completed的广播。

05行:监听系统开机广播需要声明权限。

运行程序后,将手机关机重启,就能收到这条广播了。

三、发送自定义广播

1、发送标准广播  

新建工程文件。在发广播之前,我们先定义一个广播接收器来接收此广播才行。因此,新建一个类:mybroadcastreceiver,让他继承broadcastreceiver,代码如下:

这里,当mybroadcastreceiver 收到自定义的广播时,就会执行onreceive()方法中的逻辑,弹出一个toast。

紧接着,要在清单文件androidmanifest.xml中对这个广播接收器进行注册:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

代码解释:

18行:让mybroadcastreceiver接收一条值为om.example.m05_broadcastreceiver02.my_broadcast的广播,因此待会儿在发送广播的时候,我们就需要发出这样的一条广播。

紧接着,修改activity.xml中的代码,添加一个按钮button。

然后,修改mainactivity.java中的代码,添加button的监听事件:点击按钮时,发送广播

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

总结:可以看到,点击按钮时,发送com.example.m05_broadcastreceiver02.my_broadcast这条广播,这样,所有能够监听com.example.m05_broadcastreceiver02.my_broadcast这条广播的广播接收器就都会同时收到消息,此时发出去的就是一条标准广播,即无序广播。所以接下来就需要讲到有序广播。

2、发送有序广播:

广播是一种可以跨进程的通信方式,其他应用程序是可以收到的。现在我们来发一条有序广播。

有序广播不仅有先后顺序,而且前面的广播还可以将后面的广播截断。

在3.1的代码基础之上,将按钮的监听事件修改如下:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

即将06行代码修改一下,将sendbroadcast()方法改为sendorderedbroadcast()方法,sendorderedbroadcast()方法接收两个参数,第二个参数是一个与权限相关的字符串,这里传入null即可。

紧接着,修改清单文件androidmanifest.xml中对广播接收器的注册,设置优先级:

即添加第02行代码。可以看到,通过android:priority属性给广播接收器设置了优先级。这个属性的范围在-1000到1000,数值越大,优先级越高。

接下来,如果想要拦截这个广播,防止让后面的广播接收器也接收到了这个广播。可以修改mybroadcastreceiver中的代码:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

即添加第06行代码。如果在onreceive()方法中调用了abortbroadcast()方法,就表示是将这条广播拦截,后面的广播接收器将无法再接收到。

特别关注:

广播接收器的生命周期:关键在于broadcastreceiver中的onreceive()方法,从onreceive()里的第一行代码开始,onreceive()里的最后一行代码结束。

一个广播到来的时候,用什么方式提醒用户是最友好的呢?第一种方式是吐司,第二种方式是通知。注:不要使用对话框,以免中断了用户正在进行的操作。

四、使用本地广播:

之前我们发送和接收的广播全部都是属于全局广播,即发出去的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播。这样一来,必然会造成安全问题。于是便有了本地广播:即只能在本应用程序中发送和接收广播。这就要使用到了localbroadcastmanager这个类来对广播进行管理。

我们修改2.1中动态注册广播接收器的代码,即修改mainactivity.java中的代码如下:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

注:本地广播是无法通过静态注册的方式来接收的。其实也完全可以理解,因为静态注册主要就是为了让程序在未启动的情况下也能收到广播。而发送本地广播时,我们的程序肯定是已经启动了,没有必要使用到静态注册的功能。

五、各种各样的广播: 

在android中有很多系统自带的intent.action,通过监听这些事件我们可以完成很多功能。

开机:

string boot_completed_action 广播:在系统启动后。这个动作被广播一次(只有一次)。监听: “android.intent.action.boot_completed”

电话拨入:

string answer_action 动作:处理拨入的电话。监听: “android.intent.action.answer”

电量变化:

string battery_changed_action 广播:充电状态,或者电池的电量发生变化。监听: “android.intent.action.battery_changed”

日期改变:

string date_changed_action 广播:日期被改变。 监听:“android.intent.action.date_changed”

取消更新下载:

string fota_cancel_action 广播:取消所有被挂起的 (pending) 更新下载。 监听:“android.server.checkin.fota_cancel”

更新开始安装:

string fota_ready_action 广播:更新已经被下载 可以开始安装。监听 “android.server.checkin.fota_ready”

主屏幕:

string home_category 类别:主屏幕 (activity)。设备启动后显示的第一个 activity。 监听:"android.intent.category.home”

新应用:

string package_added_action 广播:设备上新安装了一个应用程序包。监听: “android.intent.action.package_added”

删除应用:

string package_removed_action 广播:设备上删除了一个应用程序包。监听: “android.intent.action.package_removed”

屏幕关闭:

string screen_off_action 广播:屏幕被关闭。监听: “android.intent.action.screen_off”

屏幕开启:

string screen_on_action 广播:屏幕已经被打开。 监听:“android.intent.action.screen_on”

时区改变:

string timezone_changed_action 广播:时区已经改变。监听: “android.intent.action.timezone_changed”

时间改变:

string time_changed_action 广播:时间已经改变(重新设置)。 “android.intent.action.time_set”

时间流逝:

string time_tick_action 广播:当前时间已经变化(正常的时间流逝)。 “android.intent.action.time_tick”

进入大容量存储模式:

string ums_connected_action 广播:设备进入 usb 大容量存储模式。 “android.intent.action.ums_connected”

退出大容量存储模式:

string ums_disconnected_action 广播:设备从 usb 大容量存储模式退出。 “android.intent.action.ums_disconnected”

壁纸改变:

string wallpaper_changed_action 广播:系统的墙纸已经改变。 “android.intent.action.wallpaper_changed”

web搜索:

string web_search_action 动作:执行 web 搜索。 “android.intent.action.web_search”

网络变化:

string connectivity_change_action 动作:网络变化。“android.intent.action.connectivity_change_action”

六、实例:使用动态注册,监听手机的电量变化。

完整版代码如下:

(1)activity_main.xml代码如下:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

(2)mainactivity.java的代码如下:

Android组件系列----BroadcastReceiver广播接收器
Android组件系列----BroadcastReceiver广播接收器

紧接着,在清单文件中进行权限声明:

mainactivity.java的代码解释如下:

40至45行:固定代码,用于获取当前电量

48至50行:当电量低时,可以进行一些操作,例如弹出通知等

运行后,界面如下:

Android组件系列----BroadcastReceiver广播接收器

继续阅读