说来也有那么久没有发博客了,看来是该弄一篇了,对吧?

本篇博客详细讲解了Android中的BroadCastReceiver。或许这个时候你会嫌弃的说“妈的,网上百度一大把,这东西比地摊货还便宜,你觉得我还需要看吗?”。在此呢,我能做的回答就是:“如果你是一个搞了N年Android大神,那么,对不起,小弟在这里贱笑了。如果不是,那请你Shut Up,多看看->总是有多看看的好处!”,废话说了那么多,接下来就直接奔入主题吧:

对于Android中BroadCastReceiver的讲解,我们在这里分为五个部分来讲解,层层深入。小哥(妹),心急吃不了热豆腐的!!!

A:如何自定义广播接收器?其生命周期如何?其进行耗时操作的正确办法?

B:如何注册广播接收器?每种注册方式的特点以及注意事项?

C:如何发送广播给广播接收器?发送广播的方式有几种?每一种方式的特点是什么?

D:广播存在的安全隐患:

       一:如何解决本地App中广播外泄的情况?即本地应用发出广播的时候,系统内部或则其它应用接受到了该广播。

       二:如何解决外部广播传递到本地App中?即外部应用发出广播的时候,本地应用接受到了该广播。

E:Android权限知识的普及:

       一:权限的等级有几种?每一种的含义是什么?

       二:自定义权限可以解决广播的安全隐藏,那么如何自定义权限?


接下来我们正式开始讲解:

A:如何自定义广播接收器?其生命周期如何?其进行耗时操作的正确办法?

其实自定义广播接收器很简单!我们只需让我们的自定义类继承BroadcastReceiver类,并实现其onReceive()方法即可。onReceive()方法在广播接收器接收到相关广播时就会自动被系统调用。其代码实例如下:

广播接收器的生命周期与其onReceive()方法同步,两者一起产生,一起结束,并且onReceive()方法的运行时间不能超过10秒,否则系统将报ANR错误。

那么如果我们要进行耗时的操作怎么办呢?或许有人会说:“这个so easy!启动一个子线程轻松解决问题。”然而我想说的是,如果真像你说的那样做,绝对-不起什么卵用!假设我们是通过子线程来进行耗时操作,那么很有可能子线程还没结束的时候,自定义的BroadcastReceiver就先结束了,此时只有在BroadcastReceiver的宿主进程还在运行的情况下,子线程才能重新挂在其宿主进程上继续执行,否则子线程直接死亡。但是此时其宿主进程很容易在系统需要内存的时候被优先杀死,因为自定义BroadcastReceiver的结束,导致BroadcastReceive所在的宿主进程没有任何活动的组件,因此其宿主进程就属于空进程(空进程是指没有任何活动组件的进程,空进程在系统需要内存的时候会被优先杀死综上所述我们也可以得出结论:当我们需要在广播接收器里面进行耗时操作的时候,我们最好通过StartService来启动服务,完成任务。或许在这里有人会问“为什么最好通过StartService来启动服务,完成任务?而不是通过BinderService来关联服务,完成任务?”,这是因为如果我们在广播接收器里面通过BinderService去绑定服务时,那么我们就很难控制广播接收器和服务的断开,正因如此,Google官方也不允许在广播接收器里面通过BinderService去关联服务,不信的话,你可以试试的咯!难道在广播接收器里面我们就不能和服务进行愉快的通讯了吗?这个问题其实Google官方还是为大家想到了的,只是需要一定的条件而已。我们来看下面的图片:

相信大家看到了一个peekService(Context myContext, Intent service) 方法,话说这个方法有毛用呢?呵呵,其实它就是和广播接收器与服务进行通讯”有关的哈!这里我就直接说明在Google官方得到的答案哈:(这里我亲自动手测试了的哟!)

如果我们在广播接收器里面必须要和服务进行通讯,只有在满足相关服务的身上存在“关联”关系的情况下,我们就可以直接调用其peekService()函数来返回相关服务的通讯工具IBinder(当自定义时,这里需要强转),否则一律返回null。从而实现在广播接收器里面与服务进行愉快的通讯!!!哈哈,知道了没?至此,A部分就讲解完毕了。



B:如何注册广播接收器?每种注册方式的特点以及注意事项?(如果我们把A比作我们已经成功组装了一个台式主机,那么B就是让我们给台式主机指定具体的电力来源,让它成功的运转起来!)

注册广播接收器的方式有两种:一种动态,一种静态!

动态:

广播接收器动态的注册方式主要是通过RegisterReceiver(Receiver, Filter)函数实现;其中第一个参数是BroadcastReceiver,表示注册的广播接收器。第二个参数是IntentFilter,表示用来过滤ACTION的工具。从而实现广播接收器的动态注册。在这里还是给个图片加以说明吧:

前者其实就是RegisterReceiver(Receiver, Filter)方法的第一个参数,后者其实就是RegisterReceiver(Receiver, Filter)方法的第二个参数。如果不信我们就再看图:

是的,在这个图片的上方验证了我们刚刚的问题。但是下方却多出了一个unregisterReceiver(Receiver)函数!对的,你小子猜对了,这个函数的作用就是动态的注销广播接收器。既然到了这个点上了,我就再给你补充一点知识吧!上面图片的两个函数其实表示的是“Activity交互的生命周期”,或许有的同学不知道什么是“Activity交互的生命周期”,那么就请你先移步到我之前写的 ---“哎哟!蛮吊的” 之 Activity生命周期---中去了解一下,然后再回来看就明白了。其实关于上面图片表示的动态注册/注销广播接收器只是我设定的一种情况,其实还可以相应的放在“Activity显示的生命周期”或则“Activity创建与销毁的生命周期”。当然总的说来就是具体情况具体而论:怎么节约资源怎么设定!怎么符合其作用域怎么设定........!

动态注册广播接收器特点:A动态注册的广播接收器只能接受隐士Intent的广播。B动态注册广播接收器的操作和动态注销广播接收器的操作必须同时存在于同一组件的生命周期中。C动态注册的广播接收器会跟随相应的组件共存亡。

最后我再明确提一个关于动态注册/注销广播接收器的注意点:如果我们在Activity或则Service中注册了一个BroadcastReceiver,当这个Activity或则Service被销毁时如果没有注销BroadcastReceiver,系统会报一个异常,提示我们是否忘记注销广播接收器了。所以,一定要记得在特定的地方注销广播接收器。


静态:

广播接收器静态的注册方式主要是通过应用的注册表来声明的,其具体的方式我直接上图,然后再加以说明即可:

如图所示,这是静态注册广播接收器最简单和典型的案例。其中标签,标签,标签的含义自己去查吧!然后我们再看---1:receiver的android:name表示注册的广播接收器的名字,也正是因为这个特点,所以给静态广播接收器发送广播的方式不仅仅支持隐士Intent的发送,还支持当前这种显示Intent的发送。2:intent-filter的android:priority表示广播接收器接受广播时的优先级顺序。3:action的android:name表示能够发送广播给当前广播接收器的action条件字符串,只要发送广播的Intent有这个action条件字符串,即可发送广播给这个广播接收器。这里关于receiver的android:exported属性暂时不做讲解。。。

静态注册广播接收器特点:A静态注册的广播接收器不仅能接受隐式Intent的广播还能接受显示Intent的广播。B静态注册的广播接收器是常驻型的,换句话说“即使当前应用完全关闭后,如果有符合条件的广播在进行传递,这个静态广播接收器会被系统调用从而自动运行并接收广播,做出响应。

最后我再提一个关于静态注册广播接收器的注意点:注意静态注册的广播接收器的生命周期!

综上所述-建议:因为1要给动态广播接收器发送广播,我们只能通过隐式Intent的方式。2要给静态广播接收器发送广播,我们不仅能通过隐式Intent的方式,还能通过显示Intent的方式,所以为了更加简单、方便的发送广播,我们一般都采用隐式Intent的方式去统一发送广播。至此,B部分也讲解完毕了哈。



C:如何发送广播给广播接收器?发送广播的方式有几种?每一种方式的特点是什么?

我们通过Android.Content.ContextWrapper类中的SendBroadcas()系列方法实现发送广播到广播接收器

发送广播的方式有四种:

A:普通广播:SendBroadcast(Intent);

B:有序广播:SendOrderedBroadcast(Intent, ReceiverPermission);

C:普通黏粘性广播:SendStickyBroadcast(Intent);

D:有序黏粘性广播:SendStickyOrderedBroadcast(Intent, ResultReceiver, Scheduler, InitialCode, InitialData, InitialExtras);


普通广播特点:因为此种广播的传递完全是异步的,所以它的传递效率比较高。凡是可以接收此广播的广播接收器“应该”会在同一时刻接收此广播(理想状态)。不信你可以看下方的图片:


btn_1_click是我用来发送普通广播的按钮,下面就是整个流程。从图片中我们可以看到A,B,C三个广播接收器接收到广播的时间都是一样的,那就验证了上面传递效率比较高的特点,并且也验证了“凡是可以接收此广播的广播接收器“应该”会在同一时刻接收此广播(理想状态)”这一句话。


有序广播特点:A因为此种广播的传递不是异步的,所以在有很多广播接收器都可以接收此种广播的情况下,就存在一个谁先接收,谁后接收的问题,这也印证了“有序”一说,即有序广播具有有序性,但是我并没有说普通广播就不能有序化哈。B先接受此广播的广播接收器可以终止此广播的传递,即让后面原本可以接收此广播的广播接收器接收不到此广播。C先接受此广播的广播接收器可以增添额外数据并把这个数据传递给下一个接收此广播的广播接收器。

对于特点A所说的有序性我就不加以论述了,你自己看看广播接收器接收广播时的顺序就明白了哈!对于特点B而言,我想强调的是:广播接收器只能终止具有“有序性”特征的广播,否则就会报错。如果不信,你先看图:


这是广播接收器A的onReceive()方法,里面我们通过调用AbortBroadcast()方法停止了广播的传递。为了验证特点B的观点,我们分别通过btn_1_click和btn_2_click发送普通广播和有序广播,我们再来看图:

这是我们通过btn_1_click按钮发送普通广播时报的错!那么我们再来通过btn_2_click按钮发送有序广播看看,请看图片:


大家看清楚了没?前者报错,后者却好好的运行着,并且广播因为先传递给了广播接收器A,而A里面结束了广播的传递,所以后面的广播接收器B、广播接收器C都没有接收到广播,现在你总该相信我说的话了吧!

对于特点C而言,广播接收器都是通过Bundle实例绑定数据,SetResultExtras(Bundle)方法传递数据,这样就实现了数据在广播接收器中的传递。  我们现在按照广播依次传递给广播接收器A,B,C的顺序看一下传递数据的效果。当然,我们要先看广播接收器里面是怎么实现的哈,呵呵,请看图:


这是广播接收器A,B,C的实现代码哈!再看数据在广播接收器之间传递过程效果图:

btn_1_click代表发送了一次普通广播,btn_2_click代表发送了一次有序广播,结合上方的图片,是不是一下就明白了特点C的意思,并且还知道了如果不具有“有序性”特征的广播还不能传递数据,你说是不?


在讲解普通黏粘性广播和有序黏粘性广播之前,我先讲明“黏粘性广播”的特点是什么?至于原因,后面你会知道的。。。

黏粘性广播特点:黏粘性广播不像之前所说的普通广播和有序广播那样,传递完之后就消失了。而黏粘性广播产生之后,系统会自动在应用中生成一块缓存空间,当这个广播首次传递完之后就用这块缓存空间保存起来,当系统监听到有符合此黏粘性广播的广播接收器时就自动又开始发送一轮此黏粘性广播。所以,才会出现为什么当我们发送黏粘性广播有一段时间了,然后我再通过动态注册一个符合此黏粘性广播的广播接收器居然马上就收到了此广播的情况。这就是其特点,哈哈!


普通黏粘性广播特点:普通广播特点 + 黏粘性广播特点

有序黏粘性广播特点:有序广播特点 + 黏粘性广播特点

突然发现讲解黏粘性广播是不是太快了!哈哈!有些东西只能意会不能言传啊。。。至此,发送广播的方式及特点全部搞定,哦也!



D:广播存在的安全隐患:

       一:如何解决本地App中广播外泄的情况?即本地应用发出广播的时候,系统内部或则其它应用接受到了该广播。

       二:如何解决外部广播传递到本地App中?即外部应用发出广播的时候,本地应用接受到了该广播。

对于问题一,通用解决办法有两个:

        1:通过调用intent的setPackage(packageName)方法来设定此广播只在那一款应用中进行传递,当然,这里更多的是设定成本地应用的包名。

        2:通过给将要传递的广播绑定权限,指定广播接收器如果要接收此广播必须拥有的权限(即permission),否则就接收不了。

对于问题二,通用解决办法也有两个,只不过一种是解决动态注册的广播接收器,一种是解决静态注册的广播接收器:

        1:对于动态注册的广播接收器可以通过其RegisterReceiver(BroadcastReceiver, IntentFilter, String,Handler)方法来指定此广播接收器只接收拥有此权限(即permissionpermission)的广播,否则就不接收。

        2:对于静态注册的广播接收器可以通过把其注册表中对应的Receiver标签的android:exported属性设定为false来表示广播接收器对外部应用程序发出的广播不可接,即不接受来自外部应用的广播。至此,我们也知道了如何解决广播的安全隐患。但是这个时候应该有人会说:“你搞毛线啊,你说的那个权限我根本不知道是什么东西,更别说给广播接收器加权限了!你特么能说清楚点不?”对不起,我马上给你给讲解关于权限的知识点!



E:Android权限知识的普及:

       一:权限的等级有几种?每一种的含义是什么?

       二:自定义权限可以解决广播的安全隐藏,那么如何自定义权限?

对于问题一,权限的等级分为四种,其含义如下:

normal:表示的是低风险权限,此权限不会对系统、用户或其他应用程序造成危害。

dangerous:表示的是高风险权限,此权限会让系统要求用户确认相关信息,才会授予此权限。

signature:表示的是签名权限,只有在“应用程序所用的数字签名与声明此权限的应用程序所用的数字签名相同时”的情况下,才会授予此权限

signatureOrSystem:表示的是相同签名权限,只要应用程序或则Android包具有相同数字签名,就可以授予此权限这一权限适用于非常特殊的情况,比如多个供应商需要通过系统共享影像功能时。


对于问题二,我们自定义权限的方式是:

我们都是通过在应用的注册表中声明<permission/>标签来自定义权限的,下面给个图片再加以说明问题:

下面我们来讲解每个标签的含义:

android:name:此权限的唯一标识,并且这个属性是必须填写的。其它属性在未写的情况下都有指定的默认值。

android:protectionLevel:权限等级,上方已经讲解过权限等级的知识。

android:label:对权限的一个简介描述。

android:description:对权限的详细描述,分为两个部分,第一部分描述这个权限所要进行的具体操作,第二部分告诉用户授予App这个权限后会带来的后果。

android:permissionGroup:权限所属的权限组的名称。

像上方自定义权限的例子一样,以后如果我们要自定义权限时就可以这么干。呵呵,你会自定义权限了没?

注意,这里只教了大家如何去自定义权限!但是却忘了告诉大家在我们使用自定义权限之前,我们必须要再次在注册表中声明对此权限的使用说明。就像这样:

是的,现在你就可以在你的应用中使用你自定义的权限了!哇哈哈!


到这里我把我所知道关于BroadCastReceiver的所有知识都弄出来了!如有不对,欢迎指正哈!大家看看对你有没有帮助哈?当然,有帮助最好!

如果大家觉得大兄弟写的还可以就给个赞呗!呵呵,求赞哈!

如有转载,请贴上原博客的地址:http://blog.csdn.net/garlic_you_ruthless/article/details/47281463,谢谢!

更多相关文章

  1. Android中使用GPS和NetWork获取定位信息
  2. React-Native之Android(6.0及以上)权限申请
  3. Android(安卓)BroastCast的使用详解
  4. Android之——利用系统权限实现手机重启(获取系统权限签名详解)
  5. Android之使用ACTION_USAGE_ACCESS_SETTINGS权限检测手机多少天
  6. Android(安卓)壁纸设置代码 详解
  7. Android拦截电话与短信(电话拒接/短信拒收)
  8. Android(安卓)蓝牙学习
  9. 浅入浅出 Android(安卓)安全:第四章 Android(安卓)框架层安全

随机推荐

  1. textarea高度自适应自动展开
  2. javascript encodeURIComponent并将空格
  3. 使用append方法将对象转换为字符串
  4. 什么“返回此”在javascript函数中做什么
  5. 实现浮动广告的代码
  6. OnClick事件只获取第一个动态创建的行/ i
  7. 删除没有\ r \ n的换行符
  8. 为什么我的javascript/jquery代码不能像
  9. 从表的第一行和第一列中删除可选择的jque
  10. 【JavaScript】案例一:使用JS完成注册页面