Android - Activity 的生命周期

本文主要有以下几点:

  1. 什么叫返回栈?
  2. Activity 的四种状态
  3. Activity 的生命周期

1. 什么叫返回栈?

1)首先介绍什么叫栈。栈(Stack),是先进后出(FIFO,First In First Out)的数据结构,即最先进来的最后出去;而与栈相反的是队列,队列的是一种后进先出(Last In First Out)的数据结构,即最后进来的最先出去。大家可以把可以把栈想象成一个瓶子,通常瓶子只有一个口子(即是入口又是出口),我们往瓶子里扔石头,最先进来的石头被压在瓶底,最后进来的石头在瓶子的最上面,瓶底的石头想要出去,就得等最上面的石头都出去了,它才能出去;而可以把队列想象成一根两头都通的水管,一头是入口,一头是出口,同样水管里塞石头,那么最先进去的石头肯定是最先出来的;
2)而返回栈则是用于存放 Activity 的集合,每当启动一个 Activity 的时候,它就会进入返回栈,并且处于栈顶的位置(这个 Activity 处于前台);当销毁一个 Activity 的时候,就是把处于栈顶的 Activity 弹出去(即出栈),假设 A 原本处于栈顶,B 在 A 之下,由于 A 出栈了,这时 B 就会重新处于栈顶;而用户看到的就是处于栈顶的 Activity;
3)下图取自于官方文档:



从图中可以看出,原本栈中只有一个 Activity —— Activity 1,当启动第二个 Activity 时,这时原本处于栈顶的 Activity 1 就会被压到栈底,而处于栈顶的是 Activity 2,再启动第三个 Activity,这时 Activity 2 也被压到栈底,但它还是在 Activity 1 的上面,这时从返回栈中移除 Activity 3,Activity 2 将重新回到栈顶。

2. Activity 的四种状态

1)运行状态

当一个 Activity 处于前台时,即处于栈顶时,它是活动或者运行的状态。

2)暂停状态

当一个 Activity 失去焦点但仍然可见时,该 Activity 处于暂停状态(例如,在一个 Activity 上弹出一个对话框,该对话框并不铺满屏幕,原先的 Activity仍然被用户能看到)。一个处于暂停状态的 Activity 仍然是完全存活的(它会保存之前的状态和成员变量),但在内存极低的情况下会被系统杀死。

3)停止状态

但一个 Activity 完全被另一个 Activity 隐藏时,该 Activity 处于停止状态(即该 Activity 不再处于栈顶,并且不对用户来说可见时)。处于停止状态的 Activity 会保存之前的状态和成员变量,但在系统内存不够时,有可能被系统杀死(这种概率比处于暂停状态的 Activity 高)。

4)销毁状态

当一个 Activity 被移出返回栈时,它就处于销毁状态。处于销毁状态的 Activity 最有可能被系统回收。

3. Activity 的生命周期

Activity 有以下七个回调方法,这七个方法会在 Activity 生命周期的不同时刻分别被调用:<code>onCreate()</code>、<code>onStart()</code>、<code>onRestart()</code>、<code>onResume()</code>、<code>onPause()</code>、<code>onStop()</code>、<code>onDestroy()</code>。

1)七个回调方法详解


方法名称 描述 是否可被杀死 下一个被调用的方法
onCreate() Activity 第一次创建时调用,应当在此方法内完成初始化操作,如:加载布局、初始化布局中的控件等。 onStart()
onStart() Activity 由不可见变为可见时调用。当 Activity 返回前台时,onResume() 方法会在此方法执行之后被调用;当 Activity 变为不可见时,onStop() 方法会在此方法执行之后被调用。 onResume()/onStop()
onRestart() Activity 由停止状态变为运行状态之前调用,即 Activity 重新启动时调用。 onStart()
onResume() Activity 即将与用户交互之前被调用。此时 Activity 处于 Activity 堆栈的栈顶。 onPause()
onPause() 启动或恢复另一个 Activity 时被调用。应当在此方法内保存一些关键数据、释放一些消耗 CPU 的资源、停止动画等。此方法应当被迅速执行,因为只有该方法执行完成之后,下一个 Activity 才能被执行。当 Activity 返回前台时,onResume() 方法会在此方法执行之后被调用;当 Activity 变为不可见时,onStop() 方法会在此方法执行之后被调用。 Android 3.0 之前可以 onResume()/onStop()
onStop() Activity 不再可见时被调用。当 Activity 即将与用户的交互时,onRestart() 方法会在此方法执行之后被调用;当 Activity 被销毁时,onDestroy() 方法会在此方法执行之后被调用。 onRestart()/onDestroy()
onDestroy() Activity 被销毁之前最后被调用的方法。应当在此方法内释放内存。 -

2)Activity 生命周期的三个生存期(循环嵌套)


1. 完整生存期

  1. Activity 的完整生存期是指在 <code>onCreate()</code> 方法第一次被调用和 <code>onDestroy()</code> 方法最后一次被调用之间的时间段;
  2. 应当在 <code>onCreate()</code> 方法内完成初始化操作, 并在 <code>onDestroy()</code> 方法内释放内存。

2. 可见生存期

  1. Activity 的可见生存期是指在 <code>onStart()</code> 方法被调用和 <code>onStop()</code> 方法被调用之间的时间段;
  2. 在可见生存期内,Activity 是可见的,即使该 Activity 不再前台和无法与用户交互;
  3. 在 Activity 的整个生命周期,当 Activity 在对用户可见和隐藏两种状态中交替变化时,系统可能会多次调用 <code>onStart()</code> 方法和 <code>onStop()</code> 方法。

3. 前台生存期

  1. Activity 的前台生存期是指在 <code>onResume()</code> 方法被调用和 <code>onPause()</code> 方法被调用之间的时间段;
  2. 在前台生存期内,Activity 处于运行状态,位于屏幕上其他所有 Activity 之上,能与用户进行交互。

下图取自官方文档,描述了 Activity 的生命周期:


3)实例


上面讲了那么多,下面我们通过一个实例来更好地感受一下。我们来做这样一个程序:主界面上有两个按钮,按钮 A 用于跳转到另一个 Activity,按钮 B 用于弹出一个对话框。

1. 首先是主界面:


activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动第二个Activity" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="打开对话框" />
</LinearLayout>

效果:

Java 代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Button btn1;
    private Button btn2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.v(TAG, "onCreate");

        // 初始化布局中的控件
        btn1 = (Button) findViewById(R.id.btn1);
        btn2 = (Button) findViewById(R.id.btn2);

        // 设置按钮的监听器
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

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

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

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

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

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v(TAG, "onDestroy");
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn1:
                Intent intent1 = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent1);
                break;
            case R.id.btn2:
                Intent intent2 = new Intent(MainActivity.this, DialogActivity.class);
                startActivity(intent2);
                break;
            default:
                break;
        }
    }

}

2. 第二个界面:


activity_second.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".SecondActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="欢迎来到第二个Activity"
        android:gravity="center_horizontal"/>
</RelativeLayout>

Java 代码:

/**
 * Created by Monkey.C on 2016/6/24.
 */
public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }
}

3. 对话框:


activity_dialog.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".DialogActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="这是一个对话框" />
</RelativeLayout>

Java 代码:

/**
 * Created by Monkey.C on 2016/6/24.
 */
public class DialogActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialog);
    }
}

4. AndroidManifest.xml:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.monkeychan.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 第二个 Activity -->
        <activity android:name=".SecondActivity"/>
        <!-- 设置 Activity 为 对话框样式 -->
        <activity android:name=".DialogActivity" android:theme="@style/Theme.AppCompat.Dialog"/>
    </application>

</manifest>

5. 效果演示:


1. 首先运行程序:

此时的 logcat:

可以看到 MainActivity 被创建了。

2. 点击主页键,此时的 logcat:

3. 在多任务列表中找到程序,点击它,返回程序:

此时的 logcat:

4. 点击返回键,退出程序,此时的 logcat:

可以看到此时 MainActivity 被销毁了。

5. 让我们再次运行程序,此时的 logcat:

可以看到 MainActivity 被重新创建。

6. 点击按钮,启动第二个 Acitivty:

此时的 logcat:

可以看到,MainActivity 并未销毁。

7. 点击按钮,返回第一个 Acitivty,此时的 logcat:

8. 这时点击第二个按钮,弹出对话框:

此时的logcat:

可以看到只执行了 <code>onPause()</code> 方法,而没有执行 <code>onStop()</code> 方法。

9. 点击返回键,使 MainActivity 回到前台,此时的 logcat:

整个完整的操作过程:

以上就是 Activity 的生命周期。

源码下载:点这里(密码:ccsb)


参考资料:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容