处理Android应用在后台被杀死

原创 2018年04月17日 15:30:50

一、背景

        我们在使用android app的过程中,可能突然会遇到其他的事情需要将app退到后台,比如微信来了一条消息需要回复,当我们回复完消息在切换回我们的app时,如果处理不好,应用可能会白屏或者闪退。造成这种现象的原因,是android的进程回收机制,android会给每一个应用分配一定的内存,当应用退入后台时,系统并不会将应用杀死,而是将应用缓存起来。打开的应用越多,后台缓存的进程也越多,那么占用的内存也越大,当系统内存不足时,就会根据自己的一套进程回收机制去杀死应用,以便腾出内存空间来分配给其他的应用,后面会详细分析android的进程回收机制。也就是说,当我们将应用退入后台后,应用很可能会因为系统内存不足而被杀死,应用被杀死后,所有的Activity都被销毁了,但是Android也提供了一定的补救措施,activity棧并没有被清空,也就是说如果之前的Activity棧中的内容是A-->B-->C,只是ABC这三个Activity的对象被销毁了,当我们切换应用时,系统首先会重新创建Activity C,由于需要重新创建Activity实例,需要耗费一点时间,所有会有短暂的白屏现象。另外当Activity被意外杀死时,Android会调用Activity的onSaveInstance让开发者去保存应用的数据,在重新创建Activity时,会调用onRestoreInstanceState来恢复应用数据,但是针对大量需要恢复的数据,一旦处理不当,就有可能造成应用闪退,比如,应用在后台被杀死后,所有的静态变量都会被清空,这个时候我们如果直接使用这些静态变量,就会报空指针异常,从而造成程序闪退。


二、解决办法

       针对需要恢复的数据比较少的应用,我们可以通过Activity的onSaveInstance和onRestoreInstanceState去恢复,针对静态变量比较多的情况,我们可以考虑采用数据持久化的方式,所有的静态对象都改为单例模式,然后附加上一些持久化cache,空了再取缓存。嗯,这肯定也是一个办法,但是这样的束手束脚对开发来说也是痛苦,一旦处理漏了就会发生空指针异常。我们能不能换一种思路来解决上面的问题,当应用在后台被杀死时,不做Activity棧的恢复,清空Activity棧,并且直接启动应用的第一个Activity,一般是欢迎界面,这样的话,应用就相当于重启了一次,所有的逻辑都会重新开始,也就不存在静态变量为空的问题了,目前很多应用都是这样处理的。那么我们如何判断应用已经被杀死并重新创建了呢?因为静态变量的生命周期和应用的生命周期是一致的,应用被杀死后,静态变量会被回收掉,重新启动静态变量的数据会重新初始化,可以考虑定义在应用中定义一个静态变量,初始值为0,在应用的第一个界面的onCreate方法中将静态变量设置为1,表示应用走的是正常的启动流程,然后写一个基类的BaseActivity,其他的Activity都继承BaseActivity,在BaseActivity的onCreate方法中判断静态变量的值是否为1,如果不为1,则表示应用不是通过正常的流程启动的,则清空Activity棧,并启动第一个Activity。具体代码如下:

package com.liunian.androidbasic;

import android.app.Application;
import android.content.Context;
import android.content.Intent;

/**
 * Created by dell on 2018/4/13.
 */

public class App extends Application {
    public final static int APP_STATUS_KILLED = 0; // 表示应用是被杀死后在启动的
    public final static int APP_STATUS_NORMAL = 1; // 表示应用时正常的启动流程
    public static int APP_STATUS = APP_STATUS_KILLED; // 记录App的启动状态
    private static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }

    public static Context getAppContext() {
        return context;
    }

    /**
     * 重新初始化应用界面,清空当前Activity棧,并启动欢迎页面
     */
    public static void reInitApp() {
        Intent intent = new Intent(getAppContext(), SplashActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        getAppContext().startActivity(intent);
    }
}

package com.liunian.androidbasic;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

/**
 * 启动欢迎页面
 */
public class SplashActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        App.APP_STATUS = App.APP_STATUS_NORMAL; // App正常的启动,设置App的启动状态为正常启动
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);

        goMain();
    }

    /**
     * 去主页面
     */
    private void goMain() {
        Intent intent = new Intent(SplashActivity.this, MainActivity.class);
        startActivity(intent);
        finish();
    }

}
package com.liunian.androidbasic.base;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.liunian.androidbasic.App;

/**
 * Created by dell on 2018/4/17.
 * 用来处理应用在后台被杀死后,让应用重新走启动流程
 */

public abstract class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (App.APP_STATUS != App.APP_STATUS_NORMAL) { // 非正常启动流程,直接重新初始化应用界面
            Log.i("liunianprint:", "reInitApp");
            App.reInitApp();
            finish();
            return;
        } else { // 正常启动流程
            setUpViewAndData(savedInstanceState); // 子Activity初始化界面
        }
    }

    /**
     * 提供给子Activity设置界面的接口,不要在onCreate中初始化界面
     * @param savedInstanceState
     */
    protected abstract void setUpViewAndData(@Nullable Bundle savedInstanceState);
}

这里需要注意一点,继承BaseActivity的Activity初始化界面不要在onCreate中处理,而应该在setUpViewAndData处理,因为在onCreate方法中静态变量可能为空,而只有应用时正常启动时,才会调用setUpViewAndData方法。

三、总结

1、Android系统会为每一个应用分配一定的内存,当系统内存不足时,Android系统会按照进程回收机制来杀死一部分应用,并回收内存提供给其他的应用;

2、应用被系统杀死后,应用中所有的数据都会被回收掉,但是Activity提供了一定的补救措施,应用中的Activity棧还是会保存下来,并且提供了onSaveInstance和onRestoreInstanceState来恢复界面数据,因为需要重新创建Activity对象,需要耗费一定时间,所以可能会有短暂的白屏现象;

3、面对大量要恢复的数据(特别是静态变量),如果我们采用恢复数据的方式来处理应用被系统杀死的问题,代码将会很复杂,我们必须非常小心的处理数据恢复的问题,并且数据恢复也存在一定的效率问题,毕竟需要将数据持久化;

4、针对应用被杀死的问题,可以采用重新初始化应用流程的方式来解决,也就是如果发现应用时非正常启动,则清空当前Activity棧,并且去启动应用的欢迎界面,这样就相当于重新打开应用一样,这种处理方式虽然没有应用被杀死前的数据,但是处理起来简单方便。


附上源码:https://github.com/2449983723/AndroidComponents



app 在后台时间过长被杀死,及时重启

大家肯定会遇到过app退到后台,同时开启很多其他的应用,这时可能会造成我们的app因内存不足而导致进程被杀死,这时我们在从后台返回我们的app时,就会出现问题,特别是用到Application里面存储...
  • qq_35136577
  • qq_35136577
  • 2017-04-06 13:21:46
  • 1354

Android后台杀死系列之一:FragmentActivity及PhoneWindow后台杀死处理机制

App在后台久置后,再次从桌面或最近的任务列表唤醒时经常会发生崩溃,这往往是App在后台被系统杀死,再次恢复的时候遇到了问题,而在使用FragmentActivity+Fragment的时候会更加频繁...
  • happylishang
  • happylishang
  • 2017-01-10 14:04:43
  • 3037

Android 如何避免(降低)后台程序被杀?

为防止某些进程被low memory意外杀掉,可以将其加入白名单,降低误伤的概率; 一般,low memory killer会首先选择adj value徘徊在9~15的process去结束生,所以这个...
  • jinlu7611
  • jinlu7611
  • 2016-04-05 19:14:53
  • 1568

让一个Android应用一直运行在后台,不容易被杀死

使用startForeground();*在serVice的onCreat()方法中调用startForeground()方法Notification notification = new Notif...
  • MyselfGang
  • MyselfGang
  • 2016-12-27 15:46:43
  • 1989

如何让你的App永远在后台存活:对Android进程守护、闹钟后台被杀死的研究

相关阅读: 吊炸天!74款APP完整源码! 123个微信小程序源码分享(附下载) [干货]2017已来,最全面试总结——这些Android面试题你一定需要 ...
  • AMEPRE88
  • AMEPRE88
  • 2017-08-15 11:48:31
  • 1569

Android如何降低service被杀死概率

让app 的service常驻其实是很流氓的做法,但是需求摆在那里。。。 但是要清除一点:想百分百保活service在当前是无法做到的,只能降低service被杀死的概率,曾经看了多少篇网上大神的牛...
  • lhd201006
  • lhd201006
  • 2016-03-18 09:22:07
  • 7998

对Android进程守护、闹钟后台被杀死的研究

最近公司要求要做一个提醒功能,一说到提醒,那肯定就和闹钟差不多的意思,那么肯定就要用到AlarmManager。 但是,我们知道,android系统很坑爹,不同的厂商对rom的定制,导致对进程的管理都...
  • qq_25412055
  • qq_25412055
  • 2016-10-11 20:20:42
  • 9791

android 后台service 不被杀死的几种方法

自己的app的service总是容易被系统回收,搜罗了一下,基本上的解决思路有以下几种:  1.把service写成系统服务,将不会被回收(未实践):  在Manifest.xml文件中设置per...
  • sinat_30474567
  • sinat_30474567
  • 2016-06-12 15:55:11
  • 5223

Android模拟后台进程被杀

Android开发中,有时候我们需要测试下后台进程被杀,然后重新进入App时恢复现场的case。如果采用填充内存的方式,比较麻烦,下面介绍几种快速模拟后台进程被杀的方式:...
  • yinzhong39
  • yinzhong39
  • 2016-06-30 10:10:48
  • 3025

Android开发之如何保证Service不被杀掉(broadcast+system/app)

最近项目要实现这样一个效果:运行后,要有一个service始终保持在后台运行,不管用户作出什么操作,都要保证service不被kill,这可真是一个难题。参考了现今各种定制版的系统和安全厂商牛虻软件,...
  • mad1989
  • mad1989
  • 2014-03-29 16:48:06
  • 182536
收藏助手
不良信息举报
您举报文章:处理Android应用在后台被杀死
举报原因:
原因补充:

(最多只允许输入30个字)