静态广播接收者、动态广播接收者对比
用两种方式实现如下需求(使用动态和静态注册广播):编写一个程序,要求在activity中点击一个button,发送一个广播(该广播的intent中携带一个字符串数据),自定义一个广播接受者,接收到这个广播之后toast显示activity发送过来的内容。
广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出(demo中button按钮)时,广播接收器就能够收到该广播(demo中的接收广播),并在内部处理相应的逻辑(toast显示activity发送过来的内容).注册广播的方法一般有如下两种:
静态注册:在AndroidManifest.xml中注册广播。AndroidManifest中声明
动态注册:在Java代码中注册。一般用于发送频次高的广播,比如接收手机每时每刻的电量、屏幕的开启与关闭。
两种注册的区别:代码注册,它不是常驻型广播,也就是说广播跟随程序的生命周期,一旦代码所在进程被杀死,广播接收者就失效。清单文件注册是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。一旦应用程序被部署到手机,广播接收者就会生效,高版本的模拟器(3.2以上)中的接收者,需要启动过一次才能接收到广播。
动态注册的广播接收器可以自由地控制注册与注销,在灵活方面有很大的优势,但是也存在一个明显的缺点:必须程序开启后才能接收到广播,因为注册的逻辑实在onCreate方法中写的.比如我们需要让程序接收一条开机的广播,就需要使用静态注册了.
(1) 注册动态广播:
在动态广播中,首先我们创建IntentFilter的实例,并给它添加了一个值为"csdn.net.test202"的action.为什么要添加这个值呢?因为我们在点击button1时,会发出一条值为csdn.net.test202的广播(说白了,这是我们自定义的.如果是系统广播,这里的action就对应系统发送的action值.类似于一个暗号,发送暗号和接收暗号对应了,才能接收).我们的广播接收器想要监听什么广播,就要添加对应的action值.
注意,动态注册的广播接收器一定要取消注册才行.
静态广播的注册,通过android studio(as)开发工具,其实非常智能、人性化,只需要按照下图操作即可.不仅帮你生成了继承BroadcastReceiver的相关代码,AndroidManifest中的代码也生成了.但as还没智能到知道你的action值是什么.所以还需要在AndroidManifest的
(2)发送广播:
(3)接收广播:
1.上述的demo例子,其实是广播中的自定义广播,action值由自己进行定义.只需要保持发送方、接收方的action一直即可(当然最好见名之意).另外,还有一种比较常见的,就是接收系统广播,比如接收手机电量的变化、网络变化,因为广播的发送方是系统.对于这种情况,就需要使用到系统广播了.而系统广播的action值不需要记,估计你也记不住.使用到的时候,很容易搜索到.
2(面试很容易问到).上述demo中的广播接收器的onReceiver()方法中我们是通过toast进行进行演示的.在实际的项目中,往往是需要进行逻辑的处理.需要注意的是:不要在onReceiver()方法中添加过多的逻辑或者任何的耗时操作.广播接收器中是不允许开启线程的,因为BroadcastReceiver的生命周期很短(在onReceive()执行后BroadcastReceiver的实例就会被销毁),子线程可能还没有结束BroadcastReceiver就先结束了.如果BroadcastReceiver结束了,它的宿主进程还在运行,那么子线程还会继续执行。但宿主进程此时很容易在系统需要内在时被优先杀死.从而抛出ANR异常(ANR:Application Not Responding.应用程序无响应).
因此,广播更多的时候扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者开启一个服务.
3.在2中,如果我们需要进行耗时操作的话,应该通过发送Internt给Service(服务),交由它去处理.
4.广播机制简介:
广播主要分为标准广播和有序广播.其中:
标准广播(Normal Broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时间接收到这条广播,就好比中学时代,学校播音室进行听力训练,播音室发出广播后,各个班级都可以几乎同时接收到.标准广播是没有任何先后顺序可言的,它的效率会比较高,但同时意味着它是无法被截断的.
有序广播(Ordered Broadcasts)则是一种同步的广播,在广播发出后,同一时刻只会有一个广播接收器能够接收到这条消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递.就好比国家的一份重要文件,先由中央传到各省(直辖市),省(直辖市)只有执行完毕后,再传递到各市.有序广播的广播接收器是有先后顺序的,优先级高的可以先接收到广播,并且前面的广播接收器还可以拦截正在传递的广播,这样后面的广播接收器就无法收到消息了.
(标准广播工作示意图)
(有序广播工作示意图)
5.本地广播:
上面我们发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们还可以接收来自其他任何应用程序的广播.这样就很容易引起安全性的问题.比如我们发送的一些携带关键性数据的广播有可能被欺压的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播.
为了能够解决广播的安全性问题,android引入了一套本地广播体系,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全问题就不存在了.
本地广播的用法并不复杂,主要是使用一个LocalBroadcastManger来对广播进行管理,并提供了发送广播和注册广播接收器的方法.基本使用见源码LocalBroadcastActivity类.查看源码后你会发现,它的使用和动态注册广播接收器以及发送广播的代码时一样的.
另外,需要说明的是:本地广播是无法通过静态注册的方式来接收的.同时,相比系统全局广播,本地广播除了安全的优势外,还比发送系统全局广播更加高效.
1、Broadcast Receiver是什么
Broadcast是四大组件之一,是一种广泛运用在应用程序之间传输信息的机制,通过发送Intent来传送我们的数据
2、Broadcast Receiver的使用场景
同一App具有多个进程的不同组件之间的消息通信
不同App之间的组件之间的消息通信
3、Broadcast Receiver的种类
普通广播
有序广播
本地广播
Sticky广播
4、Broadcast Receiver的实现
静态注册:注册后一直运行,尽管Activity、进程、App被杀死还是可以接收到广播
动态注册:跟随Activity的生命周期
5、Broadcast Receiver实现机制
自定义广播类继承BroadcastReceiver,复写onReceiver()
通过Binder机制向AMS进行注册广播
广播发送者通过Binder机制向AMS发送广播
AMS查找符合相应条件的广播发送到BroadcastReceiver相应的循环队列中
消息队列执行拿到广播,回调BroadcastReceiver的onReceiver()
6、LocalBroadcastManager特点
本地广播只能在自身App内传播,不必担心泄漏隐私数据
本地广播不允许其他App对你的App发送该广播,不必担心安全漏洞被利用
本地广播比全局广播更高效
以上三点都是源于其内部是用Handler实现的
7、Android中跨进程通讯的几种方式
访问其他应用程序的Activity,如调用系统通话应用
Content Provider,如如访问系统相册
广播,如显示系统时间
AIDL
8.目前能否保证service不被杀死
(1)Service设置成START_STICKY
kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样
(2)提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
【结论】目前看来,priority这个属性貌似只适用于broadcast,对于Service来说可能无效·
(3)提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以在startForeground()使用startForeground()将service放到前台状态。这样在低内存时被kill的几率会低一些。
【结论】如果在极度极度低内存的压力下,该service还是会被kill掉,并且不一定会restart()
(4)onDestroy方法里重启service
service +broadcast 方式,就是当service走onDestory()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service
也可以直接在onDestroy()里startService
【结论】当使用类似口口管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证·
(5)监听系统广播判断Service状态
通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,别忘记加权限
【结论】这也能算是一种措施,不过感觉监听多了会导致Service很混乱,带来诸多不便
(6)在JNI层,用C代码fork一个进程出来
这样产生的进程,会被系统认为是两个不同的进程.但是Android5.0之后可能不行
(7)root之后放到system/app变成系统级应用
(8)大招: 放一个像素在前台(手机QQ)