第五章 全局大喇叭—详解广播机制(Broadcast Receiver )

            为什么说Android中的广播机制更加灵活啦?这是因为Android中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收自己所关心的广播内容,这些广播可能是 来自系统的,也可能是来自其他程序的。Android提供了一套完整的API,允许应用程序自由的发送和接收广播。发送广播的方法其实之前稍微提到过,如果你记性好的话可能还会有印象,就是借助我们2章学过的Intent。而接收广播的方法则需要引入一个新的概念—–广播接收者(Broadcast  Receiver)。

            广播接收器的具体用法将会在下一节中做介绍,这里我们先来了解一下广播的类型。Android中的广播主要分为两种类型:标准广播和有序广播。

      标准广播是一种完全异步执行的广播,在广播发出之后,所有你的广播接收器机会都会在同一时刻接收你这条广播消息,因此他们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。标准广播的工作看流程图5.1所示:

                  一对多,一发出其他的广播接收者同时接收

            有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先接收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了,有序广播的工作流程如图5.2所示。

也就是说广播发出以后根据优先级接收,但是上一个接收者可以阻断这条广播,阻断以后,后面的将无法接收到消息。

             掌握了这些基本概念后,我们就可以来尝试一下广播的用法了,首先就从接收系统广播开始吧。

5.2        接收系统广播

            Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机完成后会发出一条广播,店址的电量发生变化会发出一条广播,时间或时区发生改变也会发出一条广播,等等,如果想要接收到这些广播,就需要使用广播接收器,下面我们就来看一下它的具体用法。(广播接收器,可以对自己感兴趣的广播进行接收)

5.2.1    动态注册监听网络变化

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

           那么该如何创建一个广播接收器啦?其实只需要新建一个类,让他继承自BroadcastReceiver,并重写父类的onReceive()方法就行了。这样当有广播到来时,onRecive()方法就会得到执行。具体的逻辑就可以在这个方法中处理。

           那么我们就先通过动态注册的方式编写一个能够监听网络变化的程序,借此学习一下广播接收器的基本用法吧!新建一个BroadCastTest项目,然后修改MainActivity中的代码:

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

可以看到,我们早MainActivity中定义了一个内部类,NetworkChangeReceiver。这个类是继承自BroadcastReceiver的,并重写了onRecevice()方法。这样每当网络状态发生变化时,系统发出的正是一条值为

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

的广播,也就是说我们的广播接收器想要坚挺的广播,就在这里添加相应的action。接下来创建了一个NetworkChangeReceiver实例,然后调用registerReceiver()方法进行注册,将NetworkChangeReceiver实例和IntentFilter的实例都传进去,这样NetworkChangeReceiver就会接收到所有值为

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

的广播,也就实现了监听网络的功能。

最后要记住,动态注册的广播接收器一定都要取消注册才行,这里我们是在onDestroy()方法中通过调用

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

方法来实现的。整体来说,代码还是简单的,现在运行一下。首先你会在注册完成的时候收到一条广播,然后按下Home键回到主界面(注意不要按Back键,否则onDestroy()方法会执行),接着打开和关闭一下网络,你就会看到Toast提醒你网络发生变化。

          不过,只是提醒网络发生变化还不够人性化,最好是能够准备的告诉用户当前是有网络还是没有网络,因此我们还需要对上面的代码进行进一步的优化。修改MainActivity中的代码,如下:

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

         在onReceive()方法中,首先通过getSystemService()方法得到了ConnectivityManager实例,这是系统服务类,专门用于管理网络连接的。然后调用它的getActiveNetworkInfo()方法可以得到NetworkInfo的实例,接着调用NetworkInfo的isAvailable()方法,就可以判断出当前是否有网络了,最后我们还是通过Toast的方式对用户进行提示。

另外,这里有非常重要的一点需要说明,Android系统为了保护用户设备的安全和隐私,做了严格的规定:如果程序需要进行一体对用户来说比较敏感的操作,就必须在配置文件中声明权限才可以,否则程序将会直接崩溃。比如这里访问系统的网络状态就是需要声明权限的。打开AndroidManifest文件,在里面加如下权限就可以访问系统网络状态了:

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

         这是第一次遇到权限的问题,其实android中有许多操作都是需要声明权限才可以进行的,后面我们还会不断地使新的权限。不过目前这个网络访问权限还是比较简单的,只需要在AndroidMnifest里面声明一下就可以看了。然后运行一下程序。试着打开网络和关闭网络。然后就可以看见不同的toast了。

5.2.2   静态注册实现开机启动

          动态注册广播接收器可以自由的控制注册与注销,在灵活性方面有很大的优势,但是它也存在着一个缺点及必须在程序启动直接hi欧才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下就能接收到广播啦?这就需要使用静态注册的方式了。

这里我们准备让程序接收一条开机广播,当收到这条广播就可以onReceive()方法里执行相应逻辑,从而显示开机启动的功能。可以使用as提供的快捷方式来创建一个广播接收者,右击项目包(New —》 Other—》Broadcast Receiver),会弹出5.5所示的窗口

注册静态广播

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

可以看到,这里我们将广播接收器命名为myReceive,Exported属性表示是否允许这个广播接收器接受本程序以外的广播,Enabled属性表示是否启用这个广播接收器。勾选这两个属性,点击Finish完成创建。

然后修改MyReceive中的代码,如下所示:

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

代码非常简单,我们只是在onReceive()方法中使用Toast创出了一段提示信息。

另外,静态的广播接收器一定要在AndroidManifest.xml文件中注册才可以使用,不够由于我们使用as的快捷创建的广播接收器,因此注册这一步已经被自动完成了。打开配置文件文件瞧一瞧,代码如下所示:7·

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

可以看到,在《application》标签内出现了一个新的<receive>,所有的静态的广播接收器都是在这里进行注册的,他们的用法其实和activity用法很相似,而这两个属性则是根据我们刚才勾选的状态自动生成的。

不过目前 MyRevice还是不能接收开机广播的,我们还需要对Androidmanifest.xml文件进行修改才行,如下所示:

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

由于Android系统启动完成后会发出一条值为

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

          的广播,因此我们在<intent -filter>标签里添加了相应的action。另外,监听系统开机广播也需要声明权限的,可以见到,我们添加了权限

第五章     全局大喇叭---详解广播机制(Broadcast  Receiver ) - 阿里云

           现在重新运行程序后,我们的程序就已经接收开机广播了。将模拟器关闭重新启动,在启动完成之后就会收到开机广播

到目前为止,我们在广播接收器的onReceive()方法中只是简单的使用Toast提示了一段文本信息,当你整整在项目中使用它的时候,就可以在里面编写自己的逻辑了。徐璈注意的是,不允许开启线程的,当onReceive()方法运行了较长时间而没有结束时,程序就会报错。因此广播接收器更多的失败感言一种打开程序其他组建的角色,比如创建一条状态栏通知,后者启动一个服务等,这几个概念我们会在后面的章节中学习到的。(打字好球累)