写给Android初学者的基础总结(四)—— 活动的生命周期

活动的生命周期

返回栈

Android中的活动是可以层叠的。我们每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键会销毁最上面的活动,下面的一个活动就会重新显示出来。

其实Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。
在这里插入图片描述

活动状态

每个活动在其生命周期中最多可能会有4种状态。

1.运行状态

当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验。

2.暂停状态

当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。你可能会觉得既然活动已经不在栈顶了,还怎么会可见呢?这是因为并不是每一个活动都会占满整个屏幕的,比如对话框形式的活动只会占用屏幕中间的部分区域,你很快就会在后面看到这种活动。处于暂停状态的活动仍然是完全存活着的,系统也不愿意去回收这种活动(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种活动。

3.停止状态

当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收。

4.销毁状态

当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。

活动的生存期

Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节,下面就来一一介绍这7个方法。
在这里插入图片描述
在这里插入图片描述
以上7个方法中除了onRestart()方法,其他都是两两相对的,从而又可以将活动分为3种生存期。
在这里插入图片描述
在这里插入图片描述

体验活动的生命周期

点击导航栏File→Close Project。然后再新建一个ActivityLifeCycleTest项目,新建项目的过程你应该已经非常清楚了,不需要我再进行赘述,这次我们允许Android Studio帮我们自动创建活动和布局,这样可以省去不少工作,创建的活动名和布局名都使用默认值。

这样主活动就创建完成了,我们还需要分别再创建两个子活动——NormalActivity和Dialog-Activity,下面一步步来实现。

右击lntu.sc.activitylifecycletest包→New→Activity→Empty Activity,新建NormalActivity,布局起名为activity_normal。然后使用同样的方式创建DialogActivity,布局起名为activity_dialog

现在编辑activity_normal.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"
    tools:context=".NormalActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This is a normal activity"
        android:textSize="36sp"
        />
</LinearLayout>

这个布局中我们就非常简单地使用了一个TextView,用于显示一行文字

然后再编辑activity_dialog.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"
    tools:context=".DialogActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This is a dialog activity"
        android:textSize="36sp"
        />

</LinearLayout>

两个布局文件的代码几乎没有区别,只是显示的文字不同而已。NormalActivity和DialogActivity中的代码我们保持默认就好,不需要改动。其实从名字上你就可以看出,这两个活动一个是普通的活动,一个是对话框式的活动。可是我们并没有修改活动的任何代码,两个活动的代码应该几乎是一模一样的,在哪里有体现出将活动设成对话框式的呢?别着急,下面我们马上开始设置。修改AndroidManifest.xml的< activity >标签的配置,如下所示:

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ActivityLifeCycleTest">
        <activity android:name=".DialogActivity"
            android:theme="@style/Theme.AppCompat.Dialog">
        </activity>
        <activity android:name=".NormalActivity">
        </activity>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

这里是两个活动的注册代码,但是DialogActivity的代码有些不同,我们给它使用了一个android:theme属性,这是用于给当前活动指定主题的,Android系统内置有很多主题可以选择,当然我们也可以定制自己的主题,而这里@style/Theme.AppCompat.Dialog则毫无疑问是让DialogActivity使用对话框式的主题。

接下来我们修改activity_main.xml,重新定制主活动的布局,将里面的代码替换成如下内容:

<?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/start_normal_activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start NormalActivity"/>

    <Button
        android:id="@+id/start_dialog_activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start DialogActivity"
        />

</LinearLayout>

可以看到,我们在LinearLayout中加入了两个按钮,一个用于启动NormalActivity,一个用于启动DialogActivity。

最后修改MainActivity中的代码,如下所示:

package lntu.sc.activitylifecycletest;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    public static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_main);
        Button startNormalActivity = findViewById(R.id.start_normal_activity);
        Button startDialogActivity = findViewById(R.id.start_dialog_activity);
        startNormalActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, NormalActivity.class);
                startActivity(intent);
            }
        });

        startDialogActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, DialogActivity.class);
                startActivity(intent);
            }
        });
    }

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

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

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

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

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

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

在onCreate()方法中,我们分别为两个按钮注册了点击事件,点击第一个按钮会启动NormalActivity,点击第二个按钮会启动DialogActivity。然后在Activity的7个回调方法中分别打印了一句话,这样就可以通过观察日志的方式来更直观地理解活动的生命周期。

现在运行程序
在这里插入图片描述
这时观察logcat中的打印日志
在这里插入图片描述
可以看到,当MainActivity第一次被创建时会依次执行onCreate()、onStart()和onResume()方法。然后点击第一个按钮,启动NormalActivity
在这里插入图片描述
在这里插入图片描述
由于NormalActivity已经把MainActivity完全遮挡住,因此onPause()和onStop()方法都会得到执行。然后按下Back键返回MainActivity
在这里插入图片描述
由于之前MainActivity已经进入了停止状态,所以onRestart()方法会得到执行,之后又会依次执行onStart()和onResume()方法。注意此时onCreate()方法不会执行,因为MainActivity并没有重新创建。

然后再点击第二个按钮,启动DialogActivity
在这里插入图片描述
此时观察打印信息
在这里插入图片描述
可以看到,只有onPause()方法得到了执行,onStop()方法并没有执行,这是因为DialogActivity并没有完全遮挡住MainActivity,此时MainActivity只是进入了暂停状态,并没有进入停止状态。相应地,按下Back键返回MainActivity也应该只有onResume()方法会得到执行
在这里插入图片描述
最后在MainActivity按下Back键退出程序
在这里插入图片描述
依次会执行onPause()、onStop()和onDestroy()方法,最终销毁MainActivity。

实际生命周期的几种情况分析

(1)针对一个特定的Activity,第一次启动,回调如下:onCreate -> onStart ->onResume。

(2)当用户打开新的Activity或者切换到桌面的时候,回调如下:onPause ->onStop。这里有一种特殊情况,如果新Activity采用了透明主题,那么当前Activity不会回调onStop。

(3)当用户再次回到原Activity时,回调如下:onRestart -> onStart ->onResume。

(4)当用户按back键回退时,回调如下:onPause -> onStop -> onDestroy。

(5)当Activity被系统回收后再次打开,生命周期方法回调过程和(1)一样,注意只是生命周期方法一样,不代表所有过程都一样

(6)从整个生命周期来说,onCreate和onDestroy是配对的,分别标识着Activity的创建和销毁,并且只可能有一次调用。从Activity是否可见来说,onStart和onStop是配对的,随着用户的操作或者设备屏幕的点亮和熄灭,这两个方法可能被调用多次;从Activity是否在前台来说,onResume和onPause是配对的,随着用户操作或者设备屏幕的点亮和熄灭,这两个方法可能被调用多次。

如果喜欢我的文章,请记得三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持,下期更精彩!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值