Android几种Service常驻内存的小思路

来源:互联网 发布:剑网三曹雪阳脸型数据 编辑:程序博客网 时间:2024/06/05 11:28

老话说的好:躲得了初一,躲不过高三 ! 大多数的Android开发者遇到的一个问题—如何保证Service常驻内存! 最近我终于也在项目中务必幸运的遇到了

先来了解一下什么是Service常驻内存。

所谓Service常驻内存,意思就是想让自己写的Service服务在手机开机之后就永远处于运行状态。 举个Example先, 例如大家最熟悉的微信和QQ,每当手机开机之后,微信和QQ都是自动就在后台运行,实时的接收聊天信息,并且QQ和微信几乎是永远处于运行状态(即使是用户通过各种暴力方式将Service服务关掉页也没用)

再看一下Service可能被关掉的几种方式

第一种 Android系统有一个内存保护机制,当系统可用内存不足时,为了保证当前正在运行的进程(或者说Activity)能够正常运行,系统会主动的将一些优先级比较低的进程给杀掉,当然在此进程中的Service也会随着一起被杀死。

对于进程的优先级是怎么排的 可以参考一下几个优先级排序的规则 :
在Android中一共有5种进程的分类,按照优先级从高到低的顺序分别是:

  1. 前台进程

    • a . 进程中包含处于前台的正与用户交互的activity;
    • b. 进程中包含与前台activity绑定的service;
    • c. 进程中包含调用了startForeground()方法的service;
    • d. 进程中包含正在执行onCreate(), onStart(), 或onDestroy()方法的service;
    • e. 进程中包含正在执行onReceive()方法的BroadcastReceiver.
    • f. 系统中前台进程的数量很少, 前台进程几乎不会被杀死. 只有当内存低到无法保证所有的前台进程同时运行时才会选择杀死某个前台进程.
  2. 可视进程

    • a. 进程中包含未处于前台但仍然可见的activity(调用了activity的onPause()方法, 但没有调用onStop()方法). 典型的情况是运行activity时弹出对话框, 此时的activity虽然不是前台activity, 但其仍然可见.
    • b. 进程中包含与可见activity绑定的service.
    • c. 可视进程不会被系统杀死, 除非为了保证前台进程的运行而不得已为之
  3. 服务进程

    • 进程中包含已启动的service.
  4. 后台进程

    • a. 进程中包含不可见的activity(onStop()方法调用后的activity).
    • b. 后台进程不会直接影响用户体验, 为了保证前台进程/可视进程/服务进程的运行, 系统随时都有可能杀死一个后台进程.
    • c. 一个正确的实现了生命周期方法的activity处于后台时被系统杀死, 可以在用户重新启动它时恢复之前的运行状态.
  5. 空进程

    • 不包含任何处于活动状态的进程是一个空进程. 系统经常杀死空进程, 这不会造成任何影响. 空进程存在的唯一理由是为了缓存一些启动数据, 以便下次可以更快的启动.

第二种 用户可以在App管理界面主动的将Service服务强制关闭,如图所示:

这里写图片描述

第三种 就是现在市面上常见的一些Clear Master之类的App清理器,例如MIUI自带的清空RAM、手机管家、360等等。 通过这些类似的三方APP,也可以将正在运行中的进程给强制关闭

最后再来看一下我们这篇文章的主题:如何创建一个在以上三种清空下都不会被强制关闭的Service(听起来有点吊炸天的赶脚)

首先我们需要了解一点,以上三种方式其实在最终framework层都是调用PM的killProcess方法将某进程给直接杀死,但是我们在做上层App开发时(源码下的二次开发另当别论),又无法修改framework层的相关代码,所以我们不可能从根本上避开进程被杀死这一行为。

因此我的思路就是如果提供某一种机制,这种机制可以在规定时间内,频繁的去启动某Service, 而如果我们去启动一个已经被创建的Service时,它的onCreate方法是不会再被调用的。

具体实现方式有如下几种:
1 修改Service的onStartCommand方法中的返回值。onStartCommand方法有三种返回值,依次是
START_NOT_STICK:

  • 当Service被异常杀死时,系统不会再去尝试再次启动这个Service

START_STICKY

  • 当Service被异常杀死时,系统会再去尝试再次启动这个Service,但是之前的Intent会丢失,也就是在onStartCommand中接收到的Intent会是null

START_REDELIVER_INTENT

  • 当Service被异常杀死时,系统会再去尝试再次启动这个Service,并且之前的Intent也会重新被传给onStartCommand方法

通过修改onStartCommand方法的返回值这一方法足以解决上面我们提到Service被关闭的第一种情况。 但是对于用户主动强制关闭和三方管理器还是没有效果的

2 通过监听某些系统经常发出的广播,当接收到广播之后我们可以主动的去尝试启动Service,如果此Service已经被创建,则不会再走onCreate方法,否则这个Service就会被再次启动.
举几个常用的系统广播的例子:

  • Intent.ACTION_BATTERY_CH 电池电量发生改变
  • Intent.ACTION_AIRPLANE_MODE_CHANGED; 打开或关闭飞行模式
  • Intent.PHONE_STATE_CHANGED_ACTION 电话状态发生改变

这种方法可以解决Service被关闭的所有情景。 但是缺点是不是很稳定,毕竟要接收到某些系统广播之后才能执行启动Service的操作,因此有一定的延时,甚至没有成功的再次启动Service (对于希望Service被再次启动的渴望非常强烈的童鞋,不建议使用这种方法)

3 通过调用AlarmManager的setRepeating方法,我们可以每隔一段时间就去启动Service一次,代码如下所示:

Calendar cal = Calendar.getInstance();        Intent intent = new Intent(this, MyService.class);        PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);        AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);        // 每分钟启动一次,这个时间值视具体情况而定        alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 60*1000, pintent);

这种方式也可以解决Service被关闭的所有情景。并且可以在一分钟内不断的去尝试启动Service,这个时间值是可以自己调的。



应该还会有其他更好的解决办法,欢迎指正或补充

1 0
原创粉丝点击