文章目录
- Activity 的状态及生命周期
- 实现管理生命周期
- FirstActivity
- SecondActivity
- DialogActivity
- 运行结果
- 旧活动被回收了还能返回吗?
Activity 的状态及生命周期
Android 的应用程序运用 栈(Back Stack) 的思想来管理 Activity:
- 每创建一个新活动,就会覆盖在旧活动之上,相当于压入栈。
- 每当按下 返回键(Back) 或者调用 finish() ,就会销毁栈顶的 Activity,相当于弹出栈。
Activity 有四种状态:
- 运行:在栈顶时运行。
- 暂停:不再处于栈顶、但屏幕上可见时暂停。
- 停止:不再处于栈顶且屏幕上不可见时停止。
- 销毁:弹栈后销毁。
Activity 类定义了七个回调方法,覆盖了整个 Activity 生命周期:
- onCreate() :活动首次创建时;
- onStart() :活动由不可见变为可见;
- onResume() :活动位于栈顶且准备好与用户交互;
- onPause() :在系统准备去启动或者恢复另一个活动时调用,通常会释放一些占用 CPU 的资源,保存一些关键数据;
- onStop() :活动完全不可见时调用,如果新活动不是对话框式则调用
onStop,否则调用onPause; - onDestroy() :将活动变为销毁状态;
- onRestart() :将活动由停止变为运行。

实现管理生命周期
创建三个 Activity 文件以实现研究生命周期。
FirstActivity
FirstActivity 中添加两个按钮分别实现启动 普通活动 和 对话框式活动,并添加七个生命周期方法:
public class FirstActivity extends AppCompatActivity {private static final String TAG = "FirstActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);Button button_normal = (Button)findViewById(R.id.button_normal);button_normal.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(FirstActivity.this,SecondActivity.class);startActivity(intent);}});Button button_dialog = (Button)findViewById(R.id.button_dialog);button_dialog.setOnClickListener((View view)->{Intent intent = new Intent(this, DialogActivity.class);startActivity(intent);});}@Overrideprotected void onStart() {super.onStart();Log.d(TAG, "onStart: ");}@Overrideprotected void onResume() {super.onResume();Log.d(TAG, "onResume: ");}@Overrideprotected void onPause() {super.onPause();Log.d(TAG, "onPause: ");}@Overrideprotected void onStop() {super.onStop();Log.d(TAG, "onStop: ");}@Overrideprotected void onDestroy() {super.onDestroy();Log.d(TAG, "onDestroy: ");}@Overrideprotected void onRestart() {super.onRestart();Log.d(TAG, "onRestart: ");}
}
first_layout.xml 实现 FirstActivity 的具体布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button_normal"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="normal"></Button><Buttonandroid:id="@+id/button_dialog"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="dialog"></Button></LinearLayout>
SecondActivity
SecondActivity 作为一个普通活动,供 FirstActivity 的 button_normal 跳转调用,其 button2 提供一个能拨号 10086 的 intent:
public class SecondActivity extends AppCompatActivity {private static final String TAG = "SecondActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.second_layout);Button button2 = findViewById(R.id.button_2);button2.setOnClickListener((View view)->{Intent intent = new Intent(Intent.ACTION_DIAL);intent.setData(Uri.parse("tel:10086"));startActivity(intent);});}
}
second_layout.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".SecondActivity"><Buttonandroid:id="@+id/button_2"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="button_2"/></LinearLayout>
DialogActivity
创建 DialogActivity 文件,旨在实现一个对话框式的活动:
public class DialogActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.dialog_layout);}
}
想要让其实现对话框式,需要对其 activity 标签做出如下修改:

通过 android:theme 指定 DialogActivity 的主题。
PS: 书上是这么写的 android:theme="@android:style/Theme.Dialog" ,这是 Activity 的 theme,但我们默认生成的 DialogActivity 继承的是 AppCompatActivity,所以就要使用与其配合的 AppCompat 的 theme 才行。
dialog_layout.xml 文件设计布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:text="Dialog Activity"/></LinearLayout>
运行结果
点击运行,首先显示的是 FirstActivity 的界面:

此时查看 logcat,生命周期执行到 onResume 阶段:

点击 NORMAL 按钮,跳转到 SecondActivity 界面:

因此 onPause() —— FirstActivity 启动另外一个活动 SecondActivity 和 onStop() —— SecondActivity 需要占满整个屏幕,因此 FirstActivity 停止,都会被执行:

按下 Back 键返回 FirstActivity 界面,观察 logcat:

由于 FirstActivity 已经进入停止状态,因此执行 onRestart():由停止变为运行,之后重新执行 onStart() :由不可见变为可见 和 onResume :准备好与用户交互。之所以不执行 onCreate() ,是因为 FirstActivity 没有重新创建。
点击 DIALOG 按钮,跳转到 DialogActivity 界面:
此时 logcat 只有一条日志信息:

没有调用 onPause() 是因为 DialogActivity 并没有占满整个屏幕,FirstActivity 只是进入了暂停状态,没有进入停止状态。
同理按下 Back 键也只会执行 onResume() 方法,因为不用从停止状态重新变为运行。

最后在 FirstActivity 界面点击 Back 键退出程序,会依次执行:

之后便销毁了 FirstActivity。
旧活动被回收了还能返回吗?
A 活动启动 B 活动,假如此时内存空间不足,系统将 A 活动进行回收了,这时点击 Back 还能返回 A 吗?
其实 A 还是会正常显示的,只不过这时并不会执行 onRestart() 方法,而是执行 oncreate() 方法,A 会被重新创建一次。唯一的问题是 A 中暂存的临时数据都丢失了。
Activity 中提供了一个 onSaveInstanceState 的回调方法,活动在被回收之前一定会调用该方法,从而解决活动被回收时临时数据得不到保存的问题。
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);
}
将一些重要的临时数据保存在 Bundle 中,然后在 onCreate 的 Bundle 变量中提取数据。
onCreate 的 Bundle 一般都为 null ,但是如果在活动被系统回收之前有通过 onSaveInstanceState() 方法来保存数据的话,这个参数就会带有之前所保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。
