文章目录
- 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()
方法来保存数据的话,这个参数就会带有之前所保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。