这几天一直在准备考试,总算有个半天时间可以休息下,写写博客。
如何让Service keep alive是一个很常见的问题。
在APP开发过程中,需要Service持续提供服务的应用场景太多了,比如闹钟需要作出及时提醒,那么比如得有一个Service不断去比较当前时间和设置时间;QQ要能流畅的聊天,必然也需要及时接收消息等。
但是Android并没有保证Service有这样功能,毕竟一个系统面对的是用户,必然以对用户友好为先。
关于如何让Service keep alive,我在上篇博客给出的解决方案是:方案一,让服务器端发一个推送,检查Service是否还存活;方案二,将Service独立出来,运行在另一个进程中。
这两个方案有些地方需要说明和改进,然后还会有其他方案补充进来。
方案一:利用推送来确保Service存活。
方案一的做法有点“偷懒”。因为相当于把这个难题转移给推送服务提供者来处理,或者说,只需要依靠推送,就不需要自己去考虑存活问题。
推送一直是移动客户端开发的热门话题(实际上也是传统软件开发的热门话题)。
一般情况下,C/S结构(B/S是特殊的C/S结构)中的业务流程是这样的:客户端主动向服务器端发出请求,服务器端响应请求,建立二者之间的连接。通过建立的链接,双方可以发送/接收数据。最后客户端和服务器端断开连接。也就是说,客户端是主动方,是请求连接的发起者;服务器端保持对某个端口的监听(0-1023是系统端口号,比如80端口被指派给HTTP),而被动地等待客户端的连接请求。
那么推送指的是,服务器端在没有收到请求的情况下主动向客户端发送信息,比如服务器端收到一封邮件后主动发往邮件的客户端。
推送是如何实现的呢?首先,服务器端的功能还是不变,监听某个端口等待请求。然后我们可以看到,服务器端能主动发送信息的唯一时间段就是在建立了服务器端到客户端的连接之后、二者断开连接之前。因此,推送的实现就是基于保持服务器端和客户端的连接一直存在,方式可以是持续连接或者轮询。
回到Service这个问题上来,推送服务的提供者必然会保证推送技术的稳定性,依靠推送,可以唤醒我们的APP,那么保证Service的存活也就不在话下。
方案二:将Service运行在另一个进程中。
将Service放在另一个进程中,可以避免APP所在的进程因资源紧张或者被用户手动结束的时候,Service也被结束。
这个做法的另一个优点是,可以让Service独立出来,为同一个公司的不同APP提供相同的服务。比如当大部分APP都需要同一个信息的时候,为每个APP都写一个Service显然不好,这时完全可以写一个独立进程中的Service,为所有APP提供信息。
当然,这个方案有个缺点是,当某些手机助手无脑式结束掉全部的非系统进程时,Service无法存活。
方案三:让onStartCommand()函数的返回值为START_STICKY,同时在onDestroy()中重启Service
当返回值为该值时,Service被kill之后会被系统自动重启。
同时,在Service的onDestroy()中重启Service,可以给Service的重启做双重保证。
但是显然的缺点是,当APP的进程被kill后,这个方案就会失效。
方案四:使用“守护Service”。
即除了你需要存活的Service外,专门写一个Service,并使该Service运行在另一个进程中。
当两个Service中有一个Service被kill,就在另一个Service中去重启该Service。
从手机中进程的数量上判断,搜狐视频、触宝号码助手等使用的正是该方式。
方案五:将Service所在的APP提升至系统应用级别
在配置文件中的Application节点做这样的设置:android:persistent=”true”可以将APP提升至系统级别。
相信不管什么手机助手都不会去kill这一块的APP。
从手机中QQ被手动kill后系统出现的对话框判断,手机QQ正是使用的这一方案。
方案六:接收系统的广播
可以用BroadCastReceiver去接收系统的广播,比如时间变化的广播、电量变化的广播等。
这样基本上Service就无法被kill了。
总结:
能保证Service完全不会被杀死的方案是方案一和方案六。
比较轻量的方案是方案二和方案三。
我个人认为比较好的方案是方案四和方案五——那些大厂选择这样的方案是有道理的。具体使用哪个得看自己的需求。
虽然标题是说保持Service持续存活,但是并不是说一定要在任何情况下存活。十分不建议使用方案一和方案六。因为当用户发现,不管他怎么操作都无法停止一个APP时,带给他的只有恐慌,那么小手一抖的情况下,APP就只能被删除了。
本文同步更新在我的博客
Android中保持Service的存活