APP在后台被系统回收后,如何重新启动

时间:2023-02-06 13:25:58

问题:

app运行在后台,android系统会在内存不够用的时候,回收app,如果app中有全局的变量,那么再次打开app可能会出现崩溃的情况。

示例:

示例源码

public class MyApplication extends Application {

    String name;
    String getName() {
        return name;
    }
    void setName(String name) {
        this.name = name;
    }
    public static  MyApplication sMyApplication;
    public static MyApplication getApplication(){
        if (sMyApplication == null) {
            synchronized (MyApplication.class) {
                if (sMyApplication == null) {
                    return sMyApplication = new MyApplication();
                }
            }
        }
        return sMyApplication;

    }
}
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyApplication app = (MyApplication) getApplication();
        app.setName("Developer Phil");
        Toast.makeText(this, "1:" + app.getName(),Toast.LENGTH_LONG).show();
        Log.d("1:",app.getName());
        startActivity(new Intent(this, Main2Activity.class));
    }
}    
public class Main2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        Toast.makeText(this, "2:onCreate()",Toast.LENGTH_LONG).show();
        Log.d("2:onCreate()","onCreate()");

    }


    @Override
    protected void onResume() {
        super.onResume();
        MyApplication app = (MyApplication) getApplication();
        Toast.makeText(this, "2:"+app.getName().toUpperCase(),Toast.LENGTH_LONG).show();
        Log.d("2:",app.getName());
    }
}

原因:

程序之所以会崩溃掉是因为恢复之后APP的Application对象是全新的,所以缓存在Application中的用户名成员变量为空值,在程序调用String的toUpperCase()方法时由于NullPointerException而崩溃掉。

导致这个问题的主要原因是:Application对象并不是始终在内存中的,它有可能会由于系统内存不足而被杀掉(可通过下面的命令模拟)。但Android在你恢复这个应用时并不是重新开始启动这个应用,它会创建一个新的Application对象并且启动上次用户离开时的activity以造成这个app从来没有被kill掉得假象。

解决方法:

大概思路:

第一种:
A app的引导页面
B app的首页,启动模式为singleTask

app中设置一个静态变量,静态变量中的变量默认值设置为被系统回收,app正常启动后,设置为正常启动。

这样当app被回收后,再次打开app,静态变量中的变量为被系统回收,app从A界面重新启动,A启动B,由于activity栈中肯定存在B,并且B在栈底(因为B为app首页),所以启动B后,所有的activity都被清除。

实现了在保证栈顺序正确的情况下,实现了重新开启app

第二种

你也可以考虑,系统销毁activity后,再次开启app后,重新创建 Activity,使用函数 onSaveInstanceState()进行数据的保存

代码如下:

1、添加以下常量:

public static final int STATUS_FORCE_KILLED = -1;//应用在后台被强杀了
public static final int STATUS_NORMAL = 2; //APP正常态
public static final String START_LAUNCH_ACTION = "start_launch_action"; 


private int appStatus = Constants.STATUS_FORCE_KILLED; //默认为被后台回收了
private static AppUtils appStatusManager;

public static AppUtils getInstance() {
        if (appStatusManager == null) {
            appStatusManager = new AppUtils();
        }
        return appStatusManager;
    }

public int getAppStatus() {
        return appStatus;
}

public void setAppStatus(int appStatus) {
        this.appStatus = appStatus;
}

2、BaseActivity ,每一个activity都继承BaseActivity

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        switch (AppUtils.getInstance().getAppStatus()) {
            case Constants.STATUS_FORCE_KILLED:
                restartApp();
                break;
            case Constants.STATUS_NORMAL:
                break;
            default:
                break;
        }
    }

    protected void restartApp() {
        Intent intent = new Intent(this, LaunchActivity.class);
        intent.putExtra(Constants.START_LAUNCH_ACTION,Constants.STATUS_FORCE_KILLED);
        startActivity(intent);
    }
}    

3、app引导页面

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //这里设置为app正常态
        AppUtils.getInstance().setAppStatus(Constants.STATUS_NORMAL);
    }

4、app的首页

注意app的首页的启动模式一定要设置为singleTask

模拟系统回收

app运行在后台,android系统会在内存不够用的时候,回收运行在后台的app,它有以下三种作用。

  • 不保留app内存数据(全局的单例等),
  • 保留activity堆栈数据,
  • 再次开启app,会调用onCreate()重新创建栈顶的activity,

模拟:

  • terminal application

APP在后台被系统回收后,如何重新启动

  • kill掉进程

1、 按Home按键退出你的程序;
2、

 # 找到该APP的进程ID
 adb shell ps

 # 找到你APP的报名
 adb shell ps | grep your.app.package

 # 按照上述命令操作后,看起来是这样子的: 
 # USER PID PPID VSIZE RSS WCHAN PC NAME
 # u0_a198 21997 160 827940 22064 ffffffff 00000000 S your.app.package

 # 通过PID将你的APP杀掉
 adb shell kill  21997

 # APP现在被杀掉啦

不保留活动

android 系统在开发者选项中,有一个不保留活动的选项,它有以下三种作用。

  • 保留app内存数据(全局的单例等),
  • 保留activity堆栈数据,
  • 再次开启app,会调用onCreate()重新创建栈顶的activity,

参考:
不要在Android的Application对象中缓存数据!

android开发中模拟系统内存不足 应用释放的情

如何让你的app在后台被干掉后优雅的重新启动

[问答]离开应用界面一段较长的时间后再回到应用,易出现崩溃的原因