深入理解Activity及生命周期


前言

Activity是Android组件中最基本也是最为常见用的四大组件之一,而 Activity 的启动和组合方式则是该平台应用模型的基本组成部分,而 Android 系统与此不同,它会调用与其生命周期特定阶段相对应的特定回调方法来启动 Activity 实例中的代码。


提示:以下是本篇文章正文内容,供参考

一、Activity与用户交互

几乎所有activity都与用户交互,因此Activity类负责为您创建一个窗口,您可以在其中放置UI setContentView(View),activity通常以全屏窗口的形式呈现给用户,但它也可以以其他方式使用:

  1. 浮动窗口(通过R.attr.windowIsFloating设置了主题 的窗口),多窗口模式或嵌入到其他窗口。
  2. 几乎所有Activity的子类都会实现两种方法:
    onCreate(Bundle)是您初始化Activity,最重要的是,这里通常会调用setContentView(int) 一个布局资源来定义您的UI,并使用findViewById(int) 该资源来检索您需交互的UI中的小部件。
    onPause()是您与用户之间暂停与活动进行主动交互的地方,用户此时所做的任何更改都应提交(通常用于 ContentProvider保存数据),在这种状态下,activity仍在屏幕上是可见性;
  3. 要与Activity配合使用Context.startActivity(),所有activity类必须在AndroidManifest.xml 声明<activity标签。

二、Activity周期与概念

1. 理解Activity生命周期

  1. 当用户浏览、退出和返回应用时,应用中的 Activity 会在其生命周期的不同状态直间进行转换,Activity 类会提供许多回调,这些回调会让 Activity 知晓某个状态已经更改:系统正在创建、停止或恢复某个 Activity,或者正在销毁该 Activity 所在的进程。
  2. 在合适的时间执行正确的作业,并妥善处理转换,这将提升应用的稳健性和性能。例如,良好的生命周期回调实现有助于确保您的应用避免:

a.当用户在使用应用时接听来电,或切换至另一应用时崩溃。
b.当用户未积极使用它时,消耗宝贵的系统资源。
c.当用户离开应用并在稍后返回时,丢失用户的进度。
d.当屏幕在横向和纵向之间旋转时,崩溃或丢失用户的进度。

2. 生命周期概念

为了在 Activity 生命周期的各个阶段之间转换,Activity 提供了六个核心回调:onCreate()、onStart()、onResume()、onPause()、onStop() 和 onDestroy()。当 Activity 进入新状态时,系统会调用每个回调,当用户开始离开Activity时,系统会调用方法来销毁该Activity。

在这里插入图片描述

  1. 在某些情况下,此销毁只是部分销毁,Activity 有时候仍然驻留在内存中(例如当用户切换至另一应用时),并且仍然可以返回前台,如果用户返回该Activity,则Activity会从用户离开时的位置继续运行,少数应用例外,在后台运行时会受到限制,无法启动 Activity。
  2. 系统终止给定进程及其中 Activity 的可能性取决于当时 Activity 的状态。

在开发过程中,可能不需要实现所有生命周期方法。但是,请务必了解每个方法,并实现能够确保应用按用户期望的方式运行的方法,这些是非常重要

三、Activity生命周期

1. Activity四个状态

上图显示了activity活动的重要状态路径,正方形表示当Activity在活动状态之间移动时可以实现以执行操作的回调方法,彩色椭圆形是activity可以进入的主要状态,下面我们来了解各个生命周期之前,我们得先知道它的状态,那么它有几个状态呢?

a.如果Activity位于屏幕的前端(最顶层堆栈的最高位置),则该activity处于activity状态或正在运行。这通常是用户当前正在与之交互的activity。
b.如果某项activity失去了焦点,但仍呈现给用户,则它是可见的。如果一个新的非全尺寸或透明activity集中在您的activity顶部,另一个activity在多窗口模式下处于较高位置,或者该activity本身在当前窗口模式下无法聚焦,则是可能的。这样的activity是完全活着的(它维护所有状态和成员信息,并保持附加到窗口管理器中)。
c.如果一个activity完全被另一个activity遮盖,则将其停止或隐藏。它仍然保留所有状态和成员信息,但是,它对用户不再可见,因此它的窗口是隐藏的,当其他地方需要内存时,它会被系统杀死。
d.系统可以通过要求完成activity或简单地终止其进程以使其破坏而从内存中删除该activity。当再次将其显示给用户时,必须完全重新启动它并将其还原到以前的状态。

2. Activity 生命周期onCreate()

  1. onCreate():必须实现这个方法,当系统第一次创建这个activity,当activity被创建的时候,会执行基础的启动逻辑,这些逻辑代码只会发生一次在整个activity生命周期中。
    例如:实现绑定list数据,用viewModel把activity关联起来,实例化一些类变量。这个方法接受一个形参,savedInstanceState,这是一个Bundle对象,包含activity之前的状态。如果activity在此之前不存在,这个Bundle是空的。
  2. 下述code 展示 Activity 的基本设置,例如:声明界面(在 XML 布局文件中定义)、定义成员变量,以及配置某些界面,系统通过将文件的资源 ID R.layout.activity_test_main 传递给 setContentView() 来指定 XML 布局文件。
public class TestActivity extends Activity {
    private static final String GAME_STATE_KEY = "key_1";
    private String gameState;
    private TextView textView;
    private String TEXT_VIEW_KEY = "key_2";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        android.util.Log.d("TestActivity", "onCreate savedInstanceState:" + savedInstanceState);
        //检查是否正在重新创建一个以前销毁的实例
        if (savedInstanceState != null) {
            gameState = savedInstanceState.getString(GAME_STATE_KEY);
        }

        setContentView(R.layout.activity_test_main);
        textView = (TextView) findViewById(R.id.text_view);
        textView.setText("TestActivity");
    }

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

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

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

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

    @Override
    protected void onStop() {
        super.onStop();
         android.util.Log.d("TestActivity", "onStop:");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        android.util.Log.d("TestActivity", "onStop:");
    }

    //当前存在以前使用onSaveInstanceState()已保存实例时,才调用此回调。
    //在onCreate()中还原了一些状态,而在这里我们可以选择还原其他状态,可能在onStart()完成后才可用。
    //saveInstanceState捆绑包与onCreate()中使用的捆绑包相同。
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        //总是调用,以便它可以恢复视图层次超级
        super.onRestoreInstanceState(savedInstanceState);
        //从已保存的实例中恢复状态成员
        String key_2 = savedInstanceState.getString(TEXT_VIEW_KEY);
        android.util.Log.d("TestActivity", "onRestoreInstanceState key_2:" + key_2);
        textView.setText(key_2);

    }

    //当Activity可能被临时破坏时调用,在此处保存实例状态,比如横屏切换;
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        android.util.Log.d("TestActivity", "onSaveInstanceState");
        //保存用户自定义的状态
        outState.putString(GAME_STATE_KEY, gameState);
        outState.putString(TEXT_VIEW_KEY, textView.getText().toString());
        //调用父类交给系统处理,这样系统能保存视图层次结构状态
        super.onSaveInstanceState(outState);
    }
}

activity_test_main.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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button_1"
         />

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@android:string/autofill"/>
    </LinearLayout>

AndroidManifest.xlm

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

    <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/AppTheme">
        <activity android:name=".TestActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

3. onSaveInstanceState()和onRestoreInstanceState()使用

  1. 看到上面面code后,这里是为了让Activity添加额外的数据到已保存的实例状态,Activity生命周期中还有一个额外的回调方法,这些回调方法在前面的课程中没有显示。该方法是onSaveInstanceState(),系统在用户离开Activity时调用它。当系统调用此方法时,它将传递Bundle将在您的Activity意外销毁的事件中保存的对象,以便您可以向其中添加其他信息。如果系统在被销毁之后必须重新创建Activity实例,它会将相同的Bundle对象传递给您的Activity的onRestoreInstanceState()方法以及您的onCreate() 方法。

在这里插入图片描述

  1. 如上图所示:
    当系统开始停止您的Activity时,它会调用onSaveInstanceState() (1),以便您可以指定要保存的其他状态数据,以防Activity必须重新创建实例。如果Activity被破坏并且必须重新创建相同的实例,则系统将 (2) 中定义的状态数据传递给onCreate()方法 (2) 和onRestoreInstanceState()方法 (3)。
  1. 这里需注意两点:
    a.如果是用户自动按下返回键,或程序调用finish()退出程序,是不会触发onSaveInstanceState()和onRestoreInstanceState()的。
    b.每次用户旋转屏幕时,您的Activity将被破坏并重新创建。当屏幕改变方向时,系统会破坏并重新创建前台Activity,因为屏幕配置已更改,您的Activity可能需要加载替代资源(例如布局)。即会执行onSaveInstanceState()和onRestoreInstanceState()的。

onCreate()可以选择执行onRestoreInstanceState(),而不是在系统调用onStart()方法之后恢复状态。系统onRestoreInstanceState()只有在存在保存状态的情况下才会恢复,因此不需要检查是否Bundle为空。

有兴趣的同学可以参考上面code自己横竖屏演示一下。

4. Activity 生命周期onStart()和onRestart()

  1. onStart 当activity进入开始状态时,系统调用这个回调方法,这个方法将会让activity变得用户可见,app会准备进入前端和变得可交互,例如,这个方法初始化维护UI的代码,这个状态会完成的十分快,不会保留太长时间,系统将调用 onResume()方法。
  2. onRestart 只有在点击home键,当前activity处于onStop状态时,重新进入Activity,则会执行onRestart,这里需注意的是,如果当前activity被销毁,则不会再执行onRestart,重新启动activity则直接走onCreate -> onStart->onResume。

5. Activity 生命周期onResume()

  1. 当Activity 进入 Resume 状态时,系统调用 onResume() 方法,这时 是应用与用户互动的状态,这种状态"应用"会一直保持着,直到某些事件发生,让焦点远离此“应用”,比如:来电、用户导航到另一个 Activity,或设备屏幕关闭等。
  2. 当 Activity 进入Resume状态时,与 Activity 生命周期相关联的所有生命周期的”感知型组件”都将收到 ON_RESUME 事件,此时,生命周期中的可见组件且位于前台时需要运行的任何功能。
    例如:
    当发生中断事件时,Activity 进入“Pause”状态,系统调用 onPause();
  3. 如果 Activity 从“Pause”状态返回“Resume”状态,系统将再次调用 onResume() 方法。因此,您应实现 onResume(),以初始化在 onPause() 期间释放的组件,并执行每次 Activity 进入“onResume”状态时必须完成的任何其他初始化操作。

这里有个疑问,那么什么是”感知型组件“呢?下面我们来了解一下,如下code是我在新版本的AppcompatActivity(>26.1.0)写的,比较简单,也方便。

public class TestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity_layout);
        myObserve = new MyObserve();
        //在Activity中是没有getLifecycle方法,仅在AppCompatActivity使用
        getLifecycle().addObserver(myObserve);
    }
    public class MyObserve implements LifecycleObserver{
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        public void initialize(){
            android.util.Log.d(TAG,"MyObserve RESUME");
        }
 }

当前执行onResume方法时,则会紧接着执行initialize()方法;
TestActivity: onResume:
TestActivity: =============>initialize

6. Lifecycle是什么

  1. 其实Lifecycle是声明生命周期的观察者类,也是为了缩小Activity的代码量,啥意思呢,就是把Activity中生命周期的方法延伸给另外一个类,也就是和activity的生命周期关联上。
  1. 如果不使用AppCompatActivity的话,怎么使用Lifecycle添加Observe,答案可以,不过需要我们自己实现LifecycleOwner并Registry,下面来看一部code。

注册LifecycleObserver

public class MyActivityObserve implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate() {
        android.util.Log.d("TestActivity", "=============>onCreate");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {
        android.util.Log.d("TestActivity", "=============>onResume");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void onPause() {
        android.util.Log.d("TestActivity", "=============>onPause");
    }
}

绑定Activity生命周期

public class TestActivity extends Activity implements LifecycleOwner {
    private MyActivityObserve myObserve;
    private LifecycleRegistry mLifecycleRegistry;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_main);
        myObserve = new MyActivityObserve();
        mLifecycleRegistry = new LifecycleRegistry(this);
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        mLifecycleRegistry.addObserver(myObserve);

    }

    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

    @Override
    protected void onResume() {
        super.onResume();
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
    }
}

启动acitvity
10-23 07:29:15.507 21936 21936 D TestActivity: =============>onCreate
10-23 07:29:15.514 21936 21936 D TestActivity: =============>onResume
点击home键
10-23 07:31:27.195 21936 21936 D TestActivity: =============>onPause

  1. 通过如上code,我们知道了是如何通过Lifecycle 对Activity生命周期一一绑定;
    如果有多个类似的需要响应生命周期的类,Activity的生命周期函数就会变得非常臃肿,因此,Lifecycle就是为了解决这个痛点,将生命周期的响应分发到各个观察者中去,代码量蹭蹭就下来了。如:音视频播放、图片加载,这些吃内存大户,都应该响应生命周期,及时释放内存,否则很可能就会造成OOM;
  2. 还有一种是通过mLifecycleRegistry.markState(Lifecycle.State.ON_CREATE)进行注册实现,实现方式只需将mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)更改即可,关于State相关状态就不详解了,可参考如下链接:
    链接地址https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State?hl=zh-cn#ON_RESUME

7. Activity生命周期onPause和onStop

  1. onPause
    当用户要立开当前Activity时,执行onPause,但是这并不会销毁当前activity,当 Activity 进入已暂停状态时,与 Activity 生命周期相关联的所有生命周期“感知型组件”都将收到 ON_PAUSE 事件。这时,生命周期组件可以停止在组件没有位于前台时,无需运行的任何功能,例如停止相机,视频播放,等等。
    onPause() 执行非常简单,而且不一定要有足够的时间来执行保存操作。不建议使用 onPause() 来保存应用或用户数据、进行网络调用或执行数据库等相关操作。因为在该方法完成之前,此类工作可能无法完成。相反,应该在 执行onStop() 期间执行高负载的关闭操作。
    onPause()方法的完成并不意味着 Activity 离开“已暂停”状态。相反,Activity 会保持此状态,直到其恢复或变成对用户完全不可见。如果 Activity 恢复,系统将再次调用 onResume(),如果 Activity 从“已暂停”状态返回“已恢复”状态,系统会让 Activity 实例继续驻留在内存中,并会在系统调用 onResume() 时重新调用该实例。在这种情况下,您无需重新初始化在任何回调方法导致 Activity 进入“已恢复”状态期间创建的组件。如果 Activity 变为完全不可见,系统会调用 onStop()。
  2. onStop()
    Activity 不再对用户可见,也就是说已进入“已停止”状态,因而系统将调用 onStop() 。例如,当新启动的 Activity 覆盖整个屏幕时,会出现onStop这种情况。
    如果 Activity 已结束运行并即将终止,系统还可以调用 onStop(),当 Activity 进入已停止状态时,与 Activity 生命周期相关联的所有生命周期“感知型组件“都将收到 ON_STOP 事件。
    在 onStop() 方法中,应用应释放或调整在应用对用户不可见时的无用资源。例如,应用可以暂停动画效果、CPU 相对密集的关闭操作、信息保存到数据库、或从精确位置更新切换到粗略位置更新等。
    当 Activity 进入“已停止”状态时,Activity 对象会继续驻留在内存中:该对象将维护所有状态和成员信息,但不会附加到窗口管理器。Activity 恢复后,Activity 会重新调用这些信息。您无需重新初始化在任何回调方法导致 Activity 进入“已恢复”状态期间创建的组件。系统还会追踪布局中每个 View 对象的当前状态,如果用户在 EditText 微件中输入文本,系统将保留文本内容,因此您无需保存和恢复文本。

在这里插入图片描述

8. Activity生命周期onDestroy()

onDestroy()销毁 Ativity 之前调用,系统会先调用 onDestroy(),那么为什么会调用呢?如下两点:

a.Activity 即将结束(由于用户彻底关闭 Activity 或由于系统 Activity 调用 finish());
b.由于配置变更(例如设备旋转或多窗口模式),系统暂时销毁 Activity;

当 Activity 进入已销毁状态时,与 Activity 生命周期相关联的所有生命周期"感知型组件"都将收到 ON_DESTROY 事件。这时,生命周期组件可以在 Activity 被销毁之前清理所需的任何数据。
onDestroy这里就不多说了,也是Activity最后一个生命周期;

四、Activity 总结

1. Activity状态

在这里需要说一下,系统会在需要释放 RAM 时终止进程;系统终止给定进程的可能性取决于当时进程的状态。反之,进程状态取决于在进程中运行的 Activity 的状态;

在这里插入图片描述

注:系统永远不会直接终止 Activity 以释放内存,而是会终止 Activity 所在的进程。系统不仅会销毁 Activity,还会销毁在该进程中运行的所有其他内容。

2. Activity生命周期总结

如下图是Activity生命周期7个方法:
在这里插入图片描述
Activity对应的生命周期方法及描述 :
在这里插入图片描述

3. 总结

当Activity启动时,依次会调用onCreate()–>onStart()–>onResume(),而当Activity退居后台时(不可见,点击Home或者被新的Activity完全覆盖),onPause()和onStop()会依次被调用。
当Activity重新回到前台(从桌面回到原Activity或者被覆盖后又回到原Activity)时,onRestart()–>onStart()–>onResume()会依次被调用。当Activity退出销毁时(点击back键),onPause()–>onStop()–>onDestroy()会依次被调用,到此Activity的整个生命周期方法回调完成。

综上:就是Activity整个典型的生命周期过程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值