关于Android中常驻进程的思考

一.起因

1 因为去年面试猎豹的时候涉及到了这方面的东西面试过答得不好;
2. 同时平时对app使用场景的思考:常驻进程被需要的场景,例如聊天社交软件需要时刻保持“活着”准备接受信息提示用户(
例如qq,微博,微信);事实证明他们也是这么干的

二.思考

2.1 首先了解什么时候我们的app的进程被杀死的:

当系统的资源吃紧系统杀死我们的“闲置进程”或者用户使用了强制清理程序的软件我们的app的进程都会被干掉;

2.2关于app进程被杀死后是否应该重新静默唤醒的问题:

我感觉上面的两种情况都是理所应当的,但是如果想要在如聊天软件中实时提醒用户有新信息,那么这时候就要让我们的软件尽量成为打不死的小强了毕竟想实现实时,及时通信嘛。
还有就是我的app还在下载东西,这时候因为系统的资源太吃紧,将我的app进程杀掉了,这时候我感觉也是应该唤醒我的app将未完成的任务完成再释放资源的。

三.进程的分类

前台进程 Foreground process:

定义什么样的进程是前台进程:
某个进程持有一个正在与用户交互的Activity并且该Activity正处于resume的状态。
某个进程持有一个Service,并且该Service与用户正在交互的Activity绑定。
某个进程持有一个Service,并且该Service调用startForeground()方法使之位于前台运行。
某个进程持有一个Service,并且该Service正在执行它的某个生命周期回调方法,比如onCreate()、 onStart()或onDestroy()。
某个进程持有一个BroadcastReceiver,并且该BroadcastReceiver正在执行其onReceive()方法。
杀死foreground需要用户响应,因为这个安全优先级是最高的。
是用户操作所必须的,任一时间下,仅有少数进程会处于前台,仅当内存实在无法供给它们维持同时运行时才会被杀死。
一般来说,在这种情况下,设备依然处于使用虚拟内存的状态,必须要杀死一些前台进程以用户界面保持响应。
?Android会依据进程中当前活跃组件的重要程度来尽可能高的估量一个进程的级别。
比如说,如果一个进程中同时有一个服务和一个可视的activity,则进程会被判定为可视进程,而不是服务进程。

可见进程 Visible process

可见进程与前台进程相比要简单得多,首先可见进程不包含任何前台组件,也就是说不会出现上述前台进程的任何情境,
其次,可见进程依然会影响用户在屏幕上所能看到的内容,一般来说常见的可见进程情景可以分为两种:
某个进程持有一个Activity且该Activty并非位于前台但仍能被用户所看到,从代码的逻辑上来讲就是调用了onPause()后还没调用onStop()的状态,
从视觉效果来讲常见的情况就是当一个Activity弹出一个非全屏的Dialog时。
某个进程持有一个Service并且这个Service和一个可见(或前台)的Activity绑定。

服务进程 Service process

服务进程要好理解很多,如果某个进程中运行着一个Service且该Service是通过startService()启动也就是说没有与任何Activity绑定且并不属于
上述的两种进程状态,那么该进程就是一个服务进程。

后台进程 Background process

当某个进程处于后台进程时,其一般会持有一个不可见的Activity,也就是说当Activity隐藏到后台但未退出时,从代码的逻辑上来讲就是该Activity
的onStop被调用但onDestory未被执行的状态,后台进程会被系统存储在一个LRU表中以确保最近使用的进程最后被销毁。

空进程 Empty process

空进程很好理解,当某个进程不包含任何活跃的组件时该进程就会被置为空进程,空进程很容易会被系统盯上而被干掉,
但是如果系统资源充足,空进程也可以存活很久。
注意:标示进程优先级的只有两个进程的Importance等级以及adj值。其中adj的值被普遍作为标准,adj相关的详细情况请移步:
http://www.snbst.com/keji/1610/20191.html或者http://www.open-open.com/lib/view/open1472481071119.html#articleHeader9
其实这些对我们向下研究没什么太大的阻碍,只要知道他是优先级的标示就好了。

四.常驻进程的分析

4.1 进程被杀的原因基本可以分两种:

一种是因为自身的优先级太低,在系统资源吃紧的时候,先杀我们的进程
二种是用户强制干掉我们的进程

4.2 实现常驻进程的方法策略分析

一是保活,提高我们的进程优先级,尽量让我们的进程不被杀死,起到预防的作用
二是死了救活,进程被杀死之后,想办法唤起

4.3实现常驻进程的具体实施

4.3.1 保活

利用Service和Notification来提升优先级。先是将进程提升为Service进程,再结合notification提升为前台进程。
结合的原因是:从 Android4.3 开始调用 setForeground 将后台 Service 设置为前台 Service 时,必须在系统的通知栏发送一条通知,也就是前台 Service 与一条可见的通知时绑定在一起的。加入Service使进程变为服务进程,再绑定notification使其成为前台进程。但是这种方法就要提示用户了,不能默默的进行了当然这是我们作为开发者不愿看到的。
解决方法:
一个主Service,在其内部写个InnerService。在主Service中调用setForeground创建notification的同时我们去在InnerService中也创建具有相同id的notification,创建之后立刻将InnerService停止掉。这是个技巧,这么做之后会发现notification不会显示,并且我们的进程会变为前台进程。
代码如下:

public class GongService extends Service{
    public static final int START_ID = 1;
    public static GongService mLiveService;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mLiveService = this;
        return START_STICKY;
    }

    public static class InnerService extends Service{

        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            setForeGround(this);
            return super.onStartCommand(intent, flags, startId);
        }

    }

    public static void setForeGround(InnerService innerService) {
        if (mLiveService != null){
            if (Build.VERSION.SDK_INT  < Build.VERSION_CODES.JELLY_BEAN_MR2) {
                mLiveService.startForeground(START_ID, new Notification());
            } else {
                mLiveService.startForeground(START_ID, new Notification());
                if (innerService != null) {
                    innerService.startForeground(START_ID, new Notification());
                    innerService.stopSelf();
                }
            }
        }
    }
}
4.3.2进程被杀死之后,重新拉起

救活的方案是不少的,但是没有一种能百分之百的全部救活,除非是在rom级别的。像qq那种的各个手机厂商都支持它的常驻的很少。
这里只选择比较简单的方法,毕竟像流氓软件一样的长期占有内存是很可耻的。
第一种是利用Service的onStartCommand的返回值来实现Service的重启。将返回值设置为START_STICKY,至于为什么请查看上一篇文章。
第二种使用守护进程,很简单就是有A,B两个进程其中各自有一个Service,在各自的Service中轮询的拉起彼此,也就是不停的每隔一段时间就
启动一次对方。
第三种使用Native进程拉活。利用 Linux 中的 fork 机制创建 Native 进程,在 Native 进程中监控主进程的存活,当主进程挂掉后,在 Native进程中立即对主进程进行拉活。(不借助Service)
第四种利用账号同步机制拉活目前上面的几种是比较主流的几个,其中还有开源项目在做常驻框架不过也都是满足大部分的情况,不能保证百分之百。

参考:http://blog.csdn.net/yyh352091626/article/details/50542554
http://blog.csdn.net/tencent_bugly/article/details/52192423
http://blog.csdn.net/aigestudio/article/details/51348408

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值