Android学习-广播

Android中的广播主要可以分为两种类型:标准广播和有序广播。
标准广播:是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎会在同一时刻接收到这一广播信息,因此它们之间没有任何先后顺序可言。这种广播效率会比较高,但同时也意味着它是无法被截断的。标准广播的工作流程如图。
在这里插入图片描述
有序广播:则是一中同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播信息,当这个广播接收器中的逻辑执行完毕之后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。有序广播工作流程如图。
在这里插入图片描述
Android内置了很多系统级别的广播,我们可以在英雄程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一条广播,时间或者时区发生变化也会发出一条广播,等等。如果想要接收到这些广播,就需要使用广播接收器,下面我们就来看一下它的具体用法。
动态注册监听网络变化
注册广播的方式一般有两种,在代码中注册和在AndroidManifest.xml中注册,其中前者也被称为动态注册,后者也被称为静态注册。
想要创建一个广播接收器,需要新建一个类,让他继承BroadcastReceiver,并重写父类的onReceive()方法,具体逻辑在这个方法中处理。
通过动态注册的方式编写一个能监听网络变化的程序。新建一个BroadcastTest项目,然后修改MainActivity中的代码。
在这里插入图片描述
我们在main类中定义了一个内部类networkrecevicer,这个类是继承广播接收器类的,并且重写了方法。这样每当网络状态发生变化,onrececive方法就会呗执行。然后看oncreate方法,首先创建了一个Intentfilter的实例,并给他添加了一个值会android.net.conn.CONNECTIVITY_CHANGE的action,因为当网络状态发生变化时,系统发出的正是一条值为此的广播,也就是说我们的广播接收器想要监听什么广播,就在这里添加相应的action。接下来创建network接收器的实例,调用注册接收器的方法进行注册,将 network接收器和意图过滤器的实例都穿了进去,这样network接收器就会收到所有值为android.net.conn.CONNECTIVITY_CHANGE的广播,实现了监听网络变化的功能。
最后,动态注册的广播接收器一定要取消注册才行,这里实在onDestroy()方法中调用unregisterReceiver()方法来实现的。(测试时不要按back键,按home,不然会调用Destroy)。

如果想要提示当前是否有网络,可以修改活动中的代码。在这里插入图片描述
方法中,首先通过getSystemService()方法得到了ConnectivityManager的实例,这是一个系统服务类,专门用于管理网络连接的。然后调用它的getActiveNetworkInfo()方法可以得到NetworkInfo的实例,然后调用它的isAvailable()方法,就可以判断出当前是否有网络的。
这里需要声明权限,在androidmanifest.xml文件中添加下面的权限即可。在这里插入图片描述

在这里插入图片描述
静态注册实现开机启动
动态注册的广播接收器可以自由地控制注册和注销,在灵活性方面有很大的优势,但是也存在一个缺点,就是必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在oncreate()方法中的。如果想要程序在未启动的情况下就接收到广播,就需要使用静态注册的方式。
这里准备让程序接受一条开机广播,挡收到这个广播时,就可以在onreceive方法里执行相应逻辑,从而实现开机启动的功能。可以使用AS提供的快捷方式来创建一个广播接收器。
在这里插入图片描述
命名为BootCompleteReceiver,Exported属性表示是否允许这个广播接收器接收本程序以外的广播,Enabled属性表示是否启用这个广播接收器。勾选这个两个属性,点击Finish完成创建。
然后重写接收器的方法。可以先使用土司弹出一段提示信息。
另外,静态的广播接收器一定要在androidmanifest.xml文件中注册才可以使用,不过由于我们时使用AS的快捷方式进行创建,因此注册这一步已经被自动完成了。打开androidmanifest看,如下在这里插入图片描述
在这里插入图片描述
可以看到在《application》标签中出现了一个新的标签receive,所有静态的广播接收器都是在这里进行注册的。它的用法其实和activity标签非常相似,也是通过android:name来指定具体注册哪一个广播接收器,而enabled和exported属性则是刚才勾选状态生成的。
不过目前的接收器还是不能接收到开机广播的,我们还需要对androidmanifest文件进行修改才行,如下在这里插入图片描述
由于android系统启动完成后会发出一条值为android.inten.action.BOOT_COMPLETED的广播,因此我们在inten——filter的标签里添加了相应的action。另外,监听系统开机广播也时需要声明权限的,可以看到我们使用uses——permission标签又加入了一条android.permission.RECEIVE_BOOT_COMPLETED权限。
注意:不要再onreceive方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中时不允许开启线程的,挡onreceive方法运行了较长时间而没有结束时,程序就会报错。因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者启动一个服务等。

发送自定义广播
1.发送标准广播
在发送广播之前,我们还是需要先定义一个广播接收器来准备此广播才行,不然发出去也是白发,因此新建一个广播接收器并命名,代码如下在这里插入图片描述
这里当我们的接收器收到自定义的广播时,就会弹出received in MyBroadcastReceiver的提示,然后再androidmanifest中对这个广播接收器进行修改。在这里插入图片描述
这里先让接收器接受一条值为MY_BROADCAST的广播,因此待会在发送广播的时候,我们就需要发出这样一条广播。接下来就该activity_main.xml中的代码,如下在这里插入图片描述
这里,用button作为发送广播的出发点,然后修改活动中的代码
在这里插入图片描述
我们首先构建出intent对象,然后把要发送的广播的值传入,然后调用了Context的sendbroadcast方法将广播发送出去,这样所有监听MY_BROADCAST这条广播的广播接收器就会收到消息。此时发出去的广播就是一条标准广播。由于广播时使用intent进行传递的,因此你还可以在intent中携带一些数据传递给广播接收器。

发送有序广播
广播是一种可以跨进程的通信方式,这一点从前面接收系统广播的时候就看出来了。因此我们应用程序内发出的光波,其他的应用程序应该也是可以收到的。为了验证这一点,我们需要再新建一个项目,项目创建好后定义一个广播接收器,用于接收刚刚的自定义广播。新建AnotherBroadcastReceiver,代码如下在这里插入图片描述
然后再androidmanifest对这个广播接收器进行修改
在这里插入图片描述
可以看到,现在我们定义的接收器同样接受的时MY_BROADCAST这条广播。现在运行,点击button,就会分别弹出两次提示信息。目前为止,程序中发出的都是标准广播,现在我们来尝试一下发送有序广播。汇到刚刚新建的项目,修改mainactivity中的代码在这里插入图片描述
只需要改动一行代码,即为将sendBroadcast方法改成sendOrderedBroadcast方法。这个方法接收两个参数,第一个参数仍然是intent,第二个参数时一个与权限相关的字符串,这里传入null就可以了。现在重新运行程序,并且点击Button,可以发现,两个应用程序仍然都可以接收到这条广播。不过这个时候的广播接收器时又先后顺序的,而且前面的广播接收器还可以将广播截断,阻止其继续传播。
那么如何设定广播接收器的先后顺序呢,要在注册时进行设定。
修改androidmanifest中的代码。
在这里插入图片描述
通过android:priority属性给广播接收器设置了优先级,优先级比较高的广播接收器就可以先收到广播。这里将之前定义的广播接收器优先级设成100(我感觉书上这里好像错了,androidname),以保证它一定会在我们现在定义的这个接收器之前接收到广播。获得了接收广播的优先权,那么就可以选择是否允许广播继续船体了,修改获得权限的广播接收器中的代码在这里插入图片描述
如果在onReceive方法中调用了abortBroadcast()方法,就表示将这条广播截断,后面的广播接收器无法再接收这条广播。

使用本地广播
前面发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自其他任何应用程序的广播。这样就很容易引起安全性的问题,比如我们发送的一些携带关键数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。
为了能够简单的解决广播的安全性问题,android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
本地广播用法主要是使用了一个LoaclBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
修改mainacitivity中的代码
在这里插入图片描述
在这里插入图片描述
其实这基本上就和之前的动态注册广播接收器以及发送广播的代码是一样的。只不过现在首先是通过LoaclBroadcastManager的getInstance方法得到了他的一个实例,然后再注册广播接收器时调用的是localbraodcastmanager的注册方法, 在发送广播的时候调用的是local的发送方法,仅此而已。
广播的最佳实践———实现强制下线功能
实现思路:需要在界面上弹出一个对话框,让用户无法进行任何其他操作,必须要点击对话框中的确定按钮,然后回到登陆界面即可。课是这样就存在着一个问题,因为当我们被通知需要强制下线时可能正处于任何一个界面,难道需要在每个界面上都编写一个弹出对话框的逻辑?借助广播就可以轻松实现。
强制下线功能需要关闭所有的活动,然后回到登陆界面。
先创建一个AcitivityCollector类用于管理所有的活动,如下
在这里插入图片描述
然后创建BaseActivity作为所有活动的父类
在这里插入图片描述
下来部分代码比较简单,直接贴上来。在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里有一个重点,我们在Button的点击事件里面发送了一条广播,广播的值为FORCE OFFLINE,这条广播就是用于通知应用程序强制用户下线的。也就是说强制用户下线的逻辑并不是卸载mainactivity里的,应该是卸载接受这条广播的广播接收器里面,这样强制下线的功能就不会依附于任何的界面,不管是在程序的任何地方,只需要发出这样一条广播,就可以完成强制下线的操作了。
那么接下来的问题就是应该在哪里创建一个广播接收器,由于广播接收器里需要弹出一个对话框来阻塞用户的正常操作,但如果注册的是一个静态注册的接收器,时没有办法在onReceive方法里弹出对话框这样的ui控件的,而我们显然也不可能在每个活动中都去注册一个动态的广播接收器。
那我们其实只需要在baseCActivity中动态注册一个广播接收器就可以了,因为所有活动都是继承自BaseAcitivity的。修改baseacitivity中的代码。在这里插入图片描述
在这里插入图片描述
先看ForceOfflineRecevier中的代码,这里使用了AlertDialog。Builder来创建了一个对话框,注意这里一定要调用setCancelable()方法来将对话框设定为不可取消否则用户按一下back键就可以关闭对话框继续使用程序了。然后使用setPositiveButtion方法类给对话框注册确定按钮,当用户点击了确定按钮时,就调用了AcitivityCollector的finishAll方法来销毁掉所有的活动,并重新启动LoginAcitivity这个活动。
再看一下如何注册这个广播接收器的,可以看到,这里重写了onresume和onpause这两个生命周期函数,然后分别在这两个方法里去注册和取消了广播接收器。之前都是在oncreate和ondestroy方法中来注册和取消注册广播接收器。这是因为我们使用需要保证只有处于栈顶的活动才能接收到这条强制下线的广播,非战定的活动不应该也没有必要去接受这条广播,所以卸载onresume和onpause方法里就可以很好的解决这个问题,当一个活动失去栈顶位置时就会自动取消广播接收器的注册。
强制下线的逻辑已经完成了,接下来要对androidmanifest文件进行修改在这里插入图片描述
这里就是设置入口。

猜你喜欢

转载自blog.csdn.net/vbbbbbbbbbbb/article/details/113697547