Activity的重建(recreate)与恢复

关于Activity的重建可以从以下三个方面去了解:

Activity会出现重建的三种情况

  1. 系统内存不足:Activity系统会杀死一个进程,在系统需要释放内存的时候,而位于进程内的Activity就会被销毁。在用户重新回到这个Activity的时候,这个Activity就会被重建
  2. Configuration Change(Activity横竖屏切换,进入多窗口模式):在横竖屏切换时,系统为了调整布局适应新的配置,在默认情况下会重建Activity
  3. 调用Activity的onCreate()方法:主题或语言切换时可以调用onCreate重建Activity使新的主题生效

Activity在重建时的状态变化

首先我们通过一段简单代码来看一下重建过程Activity的状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class LifeCycleActivity extends AppCompatActivity {

private static final String TAG = LifeCycleActivity.class.getName();

private static final String KEY_TEST = "test";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_life_cycle);
TextView tvContent = findViewById(R.id.tv_content);
if (savedInstanceState == null) {
Log.i(TAG, " ---> first time onCreate");
} else {
Log.i(TAG, " ---> recreate");
String test = savedInstanceState.getString(KEY_TEST);
tvContent.setText(test);
}

findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
recreate();
}
});
}

@Override
protected void onStart() {
super.onStart();
Log.i(TAG, " ---> onStart");
}

@Override
protected void onResume() {
super.onResume();
Log.i(TAG, " ---> onResume");
}

@Override
protected void onPause() {
super.onPause();
Log.i(TAG, " ---> onPause");
}

@Override
protected void onStop() {
super.onStop();
Log.i(TAG, " ---> onStop");
}

@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, " ---> onDestory");
}

@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, " ---> onRestart");
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_TEST, "testing");
Log.i(TAG," ---> onSaveInstanceState");
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String test = savedInstanceState.getString(KEY_TEST);
Log.i(TAG, " ---> onRestoreInstanceState");
}
}

App运行之后切换横竖屏,通过上面代码实验得到的结果是:

1
2
3
4
5
6
7
8
9
10
11
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> first time onCreate
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onStart
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onResume
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onPause
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onSaveInstanceState
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onStop
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onDestory
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> recreate
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onStart
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onRestoreInstanceState
I/cn.appblog.activitylifecycle.LifeCycleActivity:  ---> onResume

在进入paused状态之后,会调用onSaveInstanceState去保存需要的数据状态,在重建的时候可以在onCreateonRestoreInstanceState中的参数去获取销毁前保存的数据。

Activity的状态恢复

在一些场景下你的Activity是被正常的销毁,当用户按下返回键,或者Activity内部调用finish()方法,在用户和系统的观念中这个Activity的实例是已经不再需要了。在这些场景下Activity的销毁,不需要做其他额外的工作。但是如果系统销毁Activity是由于系统的限制(configuration和memory pressure),这种情况下为了保持用户用户体验,我们需要在用户回到Activity时恢复Activity的状态。这种情况下,尽管Activity的实例已经消失,但是系统会记住Activity的实例曾经存在过。如果用户尝试重新回到Activity的时候,系统会使用Activity在被销毁时保存的状态和数据去创建一个新的Activity实例。

系统用来恢复之前的状态而保存的数据叫做instance state,是存储在Bundle中的键值对集合。默认情况下,系统使用Bundle来存储layout中View的状态(例如在EditText中输入的信息),确保Activity重建时能恢复到之前的状态。你也可以用来存储一些你想要在重建时恢复的信息,例如一些成员变量的值和用户的进度信息。

ps:为了确保系统能够恢复你Activity中View的状态,每一个View都需要有一个独特的id(通过 android:id 属性定义)

但是Bundle不适合用来保存大量的数据,因为数据在保存时需要在主线程中序列化,会消耗系统内存。如果有比较多的数据需要保存时可以结合本地存储。

View的状态系统会自动保存我们不需要做额外的操作,但是有其他数据需要存储时可以重写onSaveInstanceState方法:

1
2
3
4
5
6
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_TEST, "testing");
Log.i(TAG," ---> onSaveInstanceState");
}

数据在onCreateonRestoreInstanceState中恢复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_life_cycle);
TextView tvContent = findViewById(R.id.tv_content);
if (savedInstanceState == null) {
Log.i(TAG, " ---> first time onCreate");
} else {
Log.i(TAG, "recreate");
String test = savedInstanceState.getString(KEY_TEST);
tvContent.setText(test);
}

findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
recreate();
Intent intent = new Intent(LifeCycleActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String test = savedInstanceState.getString(KEY_TEST);
Log.i(TAG, "onRestoreInstanceState");
}

onSaveInstanceState方法并不是每次都会在onPause之后被调用,如果Activity是被明确的close(用户点击返回按钮)或者调用finish时,onSaveInstanceState不会被调用。

如果需要持久化数据,如保存到preference或database,最佳选择是Activity在前台的时候去保存,如果没有这样的机会可以在onStop方法中去保存。

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :