目录
一,Activity的生命周期
1.Activity活动栈
众所周知,Android中的Activity是可以层叠的,当我们启动一个新的Activity时,就会叠加在旧的Activity上,点击Back销毁Activity,上一个Activity就会重新显示出来,之所以会这样,是因为Android是使用活动栈(也叫返回栈)来管理Activity的。
每启动一个新的Activity,它就会在活动栈中入栈,并处于栈顶位置,按下Back健销毁Activity后,它就会出栈,下一个Activity就会重新处于栈顶位置,屏幕上显示的总是栈顶的Activity。
2.Activity状态
Activity在内存中右四种存在状态:
(1)运行状态:
当Activity处于活动栈栈顶时,Activity就处于运行状态。此时的Activity需要和用户进行交互,所以系统尽可能不会回收处于运行状态的Activity。
(2)暂停状态:
当Activity不再处于栈顶位置,但是仍然可见时,就处于暂停状态。例如弹出对话框时,对话框下面的Activity就处于暂停状态。因为暂停状态的Activity仍然可见,所以系统也是尽可能不会回收暂停状态的Activity,除非内存极低的情况,系统才会考虑回收。
(3)停止状态:
当Activity不再处于栈顶位置,并且不可见时,就处于停止状态。因为处于停止状态的Activity可能会被重新启动,所以系统会为这种Activity保存用户状态信息,但当系统内存不够时,会优先杀死该类Activity。
(4)销毁状态:
当Activity从活动栈中移除时就变成了销毁状态。系统会回收该类Activity以保证内存充足。
3.Activity状态之间的切换
Activity类中定义了七个回调方法,覆盖率Activity生命周期的每一个环节,每当Activity的状态改变时,这些方法就会被调用:
- onCreate():创建方法。在Activity第一次被创建时调用,每当我们创建一个新的Activity时,都会重写一次onCreate方法。在这个方法中应当完成加载布局和绑定事件等操作;
- onStart():启动方法。在Activity每次由不可见变为可见时调用;
- onResume():在Activity准备好与用户交互时调用,此时Activity一定位于活动栈的栈顶,并且处于运行状态;
- onPause():暂停方法。在系统准备去启动或者恢复另一个Activity时调用,或者说是当前Activity进入暂停状态之前调用。通常会在这个方法中将一些消耗CPU的资源释放,以及保存一些关键数据。这个方法的执行速度一定要快,否则会影响到新的Activity的使用;
- onStop():停止方法。这个方法在Activity完全不可见时调用。
- onDestroy():销毁方法。在Activity销毁之前调用。
- onRestart();重启方法。在Activity由停止状态变为运行状态之前调用,重启之后Activity重新位于活动栈栈顶,被用户可见;
4.代码实例体验Activity生命周期
我们可以在Activity中重写这七个回调方法,以此来更直观地来体验Activity的生命周期。
(1)分别创建NormalActivity和DialogActivity两个新的Activity,作为要跳转的Activity。其中,DialogActivity作为对话框式的Activity,在AndroidManifest.xml文件中按如下设置:
<activity
android:name=".DialogActivity"
android:theme="@style/Theme.AppCompat.Dialog"
android:exported="true" />
NormalActivity布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is NormalActivity"
android:textSize="25sp"/>
</LinearLayout>
DialogActivity布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is DialogActivity"
android:textSize="25sp"/>
</LinearLayout>
(2)以MainActivity作为主Activity,在布局文件中设置两个按钮,分别用于启动NormalActivity和DialogActivity,并在Activity中给按钮绑定监听器:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_jumpToNormalActivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="跳转到NormalActivity"
android:textSize="25sp"/>
<Button
android:id="@+id/btn_jumpToDialogActivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="跳转到DialogActivity"
android:textSize="25sp"/>
</LinearLayout>
//跳转到Normal
btn_jumpToNormalActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
jumpToNormalActivity();
}
});
//跳转到DialogActivity
btn_jumpToDialogActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
jumpToDialogActivity();
}
});
private void jumpToDialogActivity() {
Intent intent = new Intent();
intent.setClass(this, DialogActivity.class);
startActivity(intent);
}
private void jumpToNormalActivity() {
Intent intent = new Intent();
intent.setClass(this, NormalActivity.class);
startActivity(intent);
}
(3)最后在MainActivity中重写七个回调方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("msg114514", "MainActivity:onCreate");
}
@Override
protected void onStart() {
Log.i("msg114514", "MainActivity:onStrat");
super.onStart();
}
@Override
protected void onRestart() {
Log.i("msg114514", "MainActivity:onRestart");
super.onRestart();
}
@Override
protected void onResume() {
Log.i("msg114514", "MainActivity:onResume");
super.onResume();
}
@Override
protected void onPause() {
Log.i("msg114514", "MainActivity:onPause");
super.onPause();
}
@Override
protected void onStop() {
Log.i("msg114514", "MainActivity:onStop");
super.onStop();
}
@Override
protected void onDestroy() {
Log.i("msg114514", "MainActivity:onDestroy");
super.onDestroy();
}
接着我们就可以通过日志打印来观察Activity的生命周期了。
(1)首先,启动Activity,观察Logcat可以看到当MainActivity第一次被创建时会依次执行onCreate,onStart,OnResume三种方法,因为这时Activity刚被创建出来,由不可见变为了可见,并且准备好了与用户进行交互;
(2)点击按钮,启动NormalActivity,可以看到onPause,onStop方法被调用,因为这时另一个Activity被启动,并且MainActivity变为不可见状态,即进入停止状态;
(3)按下Back键返回MainActivity,观察到onRestart,onStart,onResume方法被调用,因为这时MainActivity由停止状态变为了运行状态,并且重新准备好了与用户进行交互;
(4)点击第二个按钮,启动DialogActivity,此时只有onPause方法被调用,因为MainActivity此时仍能被用户可见,也就是进入了暂停状态;
(5)按下Back键返回MainActivity,发现只有onResume方法被调用,因为之前MainActivity并没有进入停止状态;
(6)最后在MainActivity按下Back键退出程序,此时会依次执行onPause,onStop,onDestroy方法,因为MainActivity变为了不可见状态,并且退出程序后MainActivity被销毁;
至此,我们就完整地体验了一遍Activity的生命周期。
二,Activity中的数据保持
试想以下这种情况,我们在一个编辑框EditView中编写好了一些内容,但这时发生了一些突发情况使Activity进入了停止状态甚至被销毁(如:不小心点到Back键,有电话突然打进来),从而变得不可见。当我们返回这个Activity时,如果编辑框中的内容消失了,肯定会给用户带来不好的体验,那么我们该如何对这些数据进行保持和恢复呢?
1.onSaveInstanceState()
Activity提供了一个onSaveInstanceState()回调方法用于保存并恢复一些临时数据,这里的临时数据包括EditText中的内容,视频播放进度等。onSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据。Bundle的保存方法需要传入两个参数,键值和要保存的内容,键值用于从Bundle中取出数据。
public abstract void onSaveInstanceState(Bundle outState);
onSaveInstanceState()的使用具体分为两步:数据的保存与恢复;
(1)数据的保存:在Activity中重写onSaveInstanceState()方法;
@Override
public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
String text = edt_text.getText().toString();
outState.putString("edt_text", text);
}
(2)数据的取出:在我们平时一直使用的onCreate方法中有一个Bundle类型的参数savedInstanceState,我们可以通过这个参数来实现对数据的取出,取出时需要判断savedInstanceState是否为空;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null){
String text = savedInstanceState.getString("edt_text");
edt_text.setText(text);
}
}
然而实际上对于View我们并不需要进行这些操作,因为Android的View自身已经实现onSaveInstanceState()方法,这些控件本身就具有保存和恢复数据的功能,例如TextView中: