共计 3490 个字符,预计需要花费 9 分钟才能阅读完成。
最近我的项目要实现这样一个成果:运行后,要有一个 service 始终保持在后盾运行,不论用户作出什么操作,都要保障 service 不被 kill,这可真是一个难题。参考了现今各种定制版的零碎和平安厂商牛虻软件,如何能保障本人的 Service 不被杀死呢?
其实除了惯例的伎俩,咱们能够参考一下微信和 360,设置 - 程序 - 正在运行,能够看到微信是同时开启了两个过程和服务:
【有趣味能够钻研一下 守护过程 和 AIDL】
我猜测它应该是互相监听,如果有一方被 kill 掉,另一个捕捉到立刻启动,以达到 service 永远都在运行的状态,貌似 360 也是这个原理,具体是不是这个样子,还有待参考,目前我还没有参透网站监控它们是如何实现的,先简略说一下我本人的防控措施吧,首先介绍一下 Service 概念,忘性不好,反复造一下车轮,高手能够间接看最初。
Service 是在一段不定的工夫运行在后盾,不和用户交互利用组件。每个 Service 必须在 manifest 中 通过 <service> 来申明。能够通过 contect.startservice 和 contect.bindserverice 来启动。和其余的利用组件一样,运行在过程的主线程中。这就是说如果 service 须要很多耗时或者阻塞的操作,须要在其子线程中实现(或者用零碎提供的 IntentService,它继承了 Service,它解决数据是用本身新开的线程)。【当然你也能够在新的线程中 startService,这样 Service 就不是在 MainThread 了】
本地服务 Local Service 用于应用程序外部
它能够启动并运行,直至有人进行了它或它本人进行。在这种形式下,它以调用 Context.startService()启动,而以调用 Context.stopService()完结。它能够调用 Service.stopSelf() 或 Service.stopSelfResult()来本人进行。不管调用了多少次 startService()办法,你只须要调用一次 stopService()来进行服务。
【用于实现应用程序本人的一些耗时工作,比方查问降级信息,并不占用应用程序比方 Activity 所属线程,而是单开线程后盾执行,这样用户体验比拟好】
近程服务 Remote Service 用于 android 零碎外部的应用程序之间
它能够通过本人定义并裸露进去的接口进行程序操作。客户端建设一个到服务对象的连贯,并通过那个连贯来调用服务。连贯以调用 Context.bindService()办法建设,以调用 Context.unbindService()敞开。多个客户端能够绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
【可被其余应用程序复用,比方天气预报服务,其余应用程序不须要再写这样的服务,调用已有的即可】
以 startService()启动服务,零碎将通过传入的 Intent 在底层搜寻相干合乎 Intent 外面信息的 service。如果服务没有启动则先运行 onCreate,而后运行 onStartCommand(可在外面解决启动时传过来的 Intent 和其余参数),直到显著调用 stopService 或者 stopSelf 才将进行 Service。无论运行 startService 多少次,只有调用一次 stopService 或者 stopSelf,Service 都会进行。应用 stopSelf(int)办法能够保障在解决好 intent 后再进行。onStartCommand,在 2.0 后被引入用于 service 的启动函数,2.0 之前为 public void onStart(Intent intent, int startId)。
以 bindService()办法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。onBind()只有采纳 Context.bindService()办法启动服务时才会回调该办法。该办法在调用者与服务绑定时被调用,当调用者与服务曾经绑定,屡次调用 Context.bindService()办法并不会导致该办法被屡次调用。采纳 Context.bindService()办法启动服务时只能调用 onUnbind()办法解除调用者与服务解除,服务完结时会调用 onDestroy()办法。
3,领有 service 的过程具备较高的优先级
官网文档通知咱们,Android 零碎会尽量放弃领有 service 的过程运行,只有在该 service 曾经被启动 (start) 或者客户端连贯 (bindService) 到它。当内存不足时,须要放弃,领有 service 的过程具备较高的优先级。
1. 如果 service 正在调用 onCreate,onStartCommand 或者 onDestory 办法,那么用于以后 service 的过程则变为前台过程以防止被 killed。
2. 如果以后 service 曾经被启动 (start),领有它的过程则比那些用户可见的过程优先级低一些,然而比那些不可见的过程更重要,这就意味着 service 个别不会被 killed.
3. 如果客户端曾经连贯到 service (bindService), 那么领有 Service 的过程则领有最高的优先级,能够认为 service 是可见的。
4. 如果 service 能够应用 startForeground(int, Notification) 办法来将 service 设置为前台状态,那么零碎就认为是对用户可见的,并不会在内存不足时 killed。
5. 如果有其余的利用组件作为 Service,Activity 等运行在雷同的过程中,那么将会减少该过程的重要性。
保障 service 不被杀掉
StartCommond 几个常量参数简介:
1、START_STICKY
在运行 onStartCommand 后 service 过程被 kill 后,那将保留在开始状态,然而不保留那些传入的 intent。不久后 service 就会再次尝试从新创立,因为保留在开始状态,在创立 service 后将保障调用 onstartCommand。如果没有传递任何开始命令给 service,那将获取到 null 的 intent。
2、START_NOT_STICKY
在运行 onStartCommand 后 service 过程被 kill 后,并且没有新的 intent 传递给它。Service 将移出开始状态,并且直到新的显著的办法(startService)调用才从新创立。因为如果没有传递任何未决定的 intent 那么 service 是不会启动,也就是期间 onstartCommand 不会接管到任何 null 的 intent。
3、START_REDELIVER_INTENT 在运行 onStartCommand 后 service 过程被 kill 后,零碎将会再次启动 service,并传入最初一个 intent 给 onstartCommand。直到调用 stopSelf(int)才进行传递 intent。如果在被 kill 后还有未解决好的 intent,那被 kill 后服务还是会主动启动。因而 onstartCommand 不会接管到任何 null 的 intent。
public int onStartCommand(Intent intent, int flags, int startId) {
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
}
晋升 service 优先级(未胜利)
在 AndroidManifest.xml 文件中对于 intent-filter 能够通过 android:priority = “1000” 这个属性设置最高优先级,1000 是最高值,如果数字越小则优先级越低,同时实用于播送。
Android 中的过程是托管的,当零碎过程空间缓和的时候,会按照优先级主动进行过程的回收。Android 将过程分为 6 个等级, 它们按优先级程序由高到低顺次是:
1. 前台过程(FOREGROUND_APP)
2. 可视过程(VISIBLE_APP)
- 主要服务过程(SECONDARY_SERVER)
4. 后盾过程 (HIDDEN_APP)
5. 内容供给节点(CONTENT_PROVIDER)
6. 空过程(EMPTY_APP)
当 service 运行在低内存的环境时,将会 kill 掉一些存在的过程。因而过程的优先级将会很重要,能够应用 startForeground 将 service 放到前台状态。这样在低内存时被 kill 的几率会低一些。