Activity的生命周期详细分析(一)

前言

在学习和工作的过程中,那些曾经模糊的知识点逐渐地散开了迷雾,有了更好、更清晰的认识。希望可以帮助自己理解,也能帮助别人。
经验之谈,对于生命周期的理解,不要仅仅知道而已,一定要了解透彻。在TV的开发中更有体会,里面有很多的activity,设置卫星搜索参数、STB设置、搜索节目后播放等。在这过程中,视图初始化,数据初始化、加载、与保存,内存泄漏等等问题,多要对生命周期要有透彻的理解,才能将代码写得更好,更优化,
我们知道,现在的应用很少会有一个单独activity,多是由多个彼此松散联系的activity组成。那从一个activity跳转到另一个 activity后,其生命周期有什么变化?接下来就聊聊关于activity的生命周期的知识点。

Activity生命周期介绍

Activity 是一个应用组件,用户可与其提供的屏幕进行交互。 每个 Activity 都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并浮动在其他窗口之上。
当activity在android应用中运行,它的活动状态是以activity的栈的形式管理的。即,每当新的 Activity 启动时,前一个 Activity 便会停止,但系统会在堆栈(“返回栈”)中保留该 Activity。新的 Activity 启动时,系统会将其推送到返回栈上,并取得用户焦点。 返回栈遵循基本的“后进先出”堆栈机制,因此,当用户完成当前 Activity 并按“返回”按钮时,系统会从堆栈中将其弹出(并销毁),然后恢复前一 Activity。( 注意:这里不单独是当前应用的Activity ,也可以是其他app的Activity 。)从而,每个activity多可能经历了生命周期中的不同状态。

关于生命周期的流程图,我们可以参考该图,如图所示:

生命周期与回调的流程图

这个也是官方里面的生命周期流程图,这个图是金字塔模型,清晰的显示每个状态,标出了前一个状态进入另一个状态需要调用的方法。确实是比Dev Guide里面的生命周期图更加容易理解,更加形象。Activity 主要目的是和用户交互,那么Resumed状态(用户能够交互的状态)就在塔顶,两边的阶梯就是用户进入和离开的状态。

生命周期的状态

由上面的流程图可看出, Activity 有很多个生命状态。然而,其中只有三个状态是静态的,这三个状态下activity可以存在一段比较长的时间,所以,Activity 基本以这三种状态存在:

  • Resumed: 此 Activity 位于屏幕前台并具有用户焦点,可以与它进行交互。(也称此状态称作“running”)

  • Paused:另一个 Activity 位于屏幕前台并具有用户焦点,但此 Activity 仍可见。也就是说,另一个 Activity 显示在此 Activity 上方,并且该 Activity 部分透明或未覆盖整个屏幕。 暂停的 Activity 处于完全活动状态(Activity 对象保留在内存中,它保留了所有状态和成员信息,并与窗口管理器保持连接),但在内存极度不足的情况下,可能会被系统终止。

  • Stopped:该 Activity 被另一个 Activity 完全遮盖(该 Activity 目前位于“后台”)。 已停止的 Activity 同样仍处于活动状态(Activity 对象保留在内存中,它保留了所有状态和成员信息,但未与窗口管理器连接)。 不过,它对用户不再可见,在他处需要内存时可能会被系统终止。

    其他状态(Created、Started、Destroyed),很快就切换掉,停留的时间比较短暂。也就是说,在系统调用onCreate(), 之后会迅速调用onStart(), 之后再迅速执行onResume()。上面就是基本的activity生命状态。

生命周期的回调

当一个 Activity 转入和转出上述不同状态时,系统会通过各种回调方法向其发出通知。 所有回调方法都是挂钩,您可以在 Activity 状态发生变化时替代这些挂钩来执行相应操作。我们进行实践,验证这些流程。
如果当前只有一个activity,生命周期的流程如下:
onCreate( ) -> onStart( ) -> onResume( ) ->onPause( ) -> onStop( ) -> onDestroy( )
这个比较简单,这里就不做太多介绍。现在我们看看有2个activity的时候是怎么调用的,这也是我们在开发必须遇到的。先给出要运行的代码,首先创建第一个activity:

public class FirstActivity extends Activity {

    private static final String TAG = "Test";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // The activity is being created.
        super.onCreate(savedInstanceState);
        Log.e(TAG, "A -> onCreate()...");
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e(TAG, "A -> onRestart()...");
    }

    @Override
    protected void onStart() {
        // The activity is about to become visible.
        super.onStart();
         Log.e(TAG, "A -> onStart()...");
    }

    @Override
    protected void onResume() {
        // The activity has become visible (it is now "resumed").
        super.onResume();
        Log.e(TAG, "A -> onResume()...");
    }

    @Override
    protected void onPause() {
        // Another activity is taking focus (this activity is about to be "paused").
        super.onPause();
        Log.e(TAG, "A -> onPause()...");
    }

    @Override
    protected void onStop() {
        // The activity is no longer visible (it is now "stopped")
        super.onStop();
        Log.e(TAG, "A -> onStop()...");
    }

    @Override
    protected void onDestroy() {
        // The activity is about to be destroyed.
        super.onDestroy();
        Log.e(TAG, "A -> onDestroy()...");
    }

    /*
     * 转入B activity
     */
    public void enterB(View view){
        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
    }
}

对应的布局也很简单,只是一个按钮,用来转入B界面,但注意要添加onclick属性哦:

<Button
       android:onClick="enterB" 
       android:id="@+id/btn_first"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="转入B界面"/>

然后创建第2个Activity,SecondActivity,它和FirstActivity 几乎一样,这里就不贴出代码了。布局也只是一个TextView,比较简单。

好,现在我们开始运行代码,一步一步来观察回调方法的执行:
进入FirstActivity ,其调用的方法有:
这里写图片描述

点击“按钮”,进入SecondActivity,其调用的方法有:
这里写图片描述

再点击Back键,退出SecondActivity,其调用的方法有:
这里写图片描述

再点击Back键,退出FirstActivity ,其调用的方法有:
这里写图片描述

这是完全覆盖的情况,一般情况下,我们见到的也是完全的覆盖的情况。但还有一种情况,就是另一个 Activity 显示在此 Activity 上方,并且该 Activity 部分透明或未覆盖整个屏幕(刚开始还不知道还可以这样子)。很简单,直接在AndroidManifest.xml中的配置,将:
android:theme属性设置为@android:style/Theme.Dialog。

现在修改了配置,再来看看变化的情况:

进入FirstActivity ,其调用的方法有:
这里写图片描述

点击“按钮”,进入SecondActivity,其调用的方法有:
这里写图片描述

再点击Back键,退出SecondActivity,其调用的方法有:
这里写图片描述

再点击Back键,退出FirstActivity ,其调用的方法有:
这里写图片描述

根据这些打印信息,可以很好的验证上面的生命周期流程图。在这过程中,也加深了我们对生命周期的理解,同时也获取一些信息。
首先,看看这2种情况主要的区别
在创建SecondActivity时:
1.在完全覆盖的情况,FirstActivity 会调用onstop(),那么在重新创建时,则会调用onRestart()方法。
2.在没有完全覆盖时,则不会调用onstop(),也不会调用onRestart()。而只是调用onPause()和onResume()。
很容易理解,只要FirstActivity 仍然被部分可见,那么FirstActivity 则一直处于Paused状态。
那么注意了,在重新创建FirstActivity ,需要刷新数据时,不能脑子一热就在onRestart()/onStart()中敲起来,在第2中情况,它是不会执行这个回调方法的。不过,我们大部分多是在onResume()加载的,这里提醒下。

其次,我们还要注意一些回调方法调用顺序的细节:(注意:也是很多人比较模糊的)
SecondActivity是在什么时候被创建的?
根据打印可以知道,不管在哪种情况,多是在FirstActivity 执行完onPause()之后才开始创建SecondActivity。那么我们在代码中就要注意,不要在onPause()执行耗时的操作,方法中的任何阻止过程都会妨碍向下一个 Activity 的转变并拖慢用户体验,如果会执行onStop(),尽量将这些操作尽量放在onStop()中。

回调方法的作用介绍

onCreate() 创建你的Activity
必须实现改方法来执行程序启动所需要的基本逻辑,且只会执行一次。该方法一般执行activity所需要的一些基础操作。如,声明UI元素 ,定义成员变量,配置UI等。(onCreate里面尽量少做事情,避免程序启动太久都看不到界面)
其还包含了一个参数叫做savedInstanceState,是用来保存Activity 状态。

onDestroy() 销毁Activity
生命周期最后调用的一个方法,系统会执行这个方法作为你 的activity要从系统中完全移除的信号。如果你的activity包含了你在onCreate时创建的后台线程,或者是其他有可能导致内存泄漏的资源,你应该在OnDestroy()时杀死他们。

onPause() 暂停你的Activity
用户要离开activtiy的第一个信号,但你的activity仍然处于部分可见的状态,但大多数时候,那意味着用户正在离开这个activity并马上会进入Stopped state. 你通常应该在onPause()回调方法里面做下面的事情:

  • 停止动画或者是其他正在运行的操作,那些都会导致CPU的浪费.
  • 提交没有保存的改变,但是仅仅是在用户离开时期待保存的内容(例如邮件草稿).
  • 释放系统资源,例如broadcast receivers, sensors (比如GPS),Camera 或者是其他任何会影响到电量的资源。

通常,如果你的activity实际上是要被Stop,不应该在onPause()时执行耗时的工作,例如写数据到DB,因为它会导致切换到下一个activity变得缓慢(你应该把那些heavy-load的工作放到onStop()去做)。

onResume() 恢复你的activity
在 Activity 即将开始与用户进行交互之前调用。 此时,Activity 处于 Activity 堆栈的顶层,并具有用户输入焦点。并且,从Paused状态恢复你的activity时,系统会调用该方法 。注意,系统每次调用这个方法时,activity都处于最前台,包括第一次创建的时候。所以,你应该实现onResume()来初始化那些你在onPause方法里面释放掉的组件,并执行那些activity每次进入Resumed state都需要的初始化动作 (例如开始动画与初始化那些只有在获取用户焦点
时才需要的组件)
不需要在恢复到Resumed state状态前重新初始化那些被保存在内存中的组件。系统同样保存了每一个在布局中的视图的当前状态,如果用户在EditText组件中输入了text,它会被保存,因此不需要保存与恢复它

onStop() 停止你的activity
调用改方法后,activity不再可见,并且应该释放那些不再需要的所有资源。在极端情况下,系统会直接杀死你的app进程,并且不执行activity的onDestroy()回调方法, 因此你需要使用onStop()来释放资源,从而避免内存泄漏。(这点需要注意)

onStart() onRestart() 启动与重启你的activity
activity从Stopped状态回到前台时,它会调用onRestart().系统再调用onStart()方法。onRestart()方法则是只在activity从stopped状态恢复时才会被调用。使用onRestart()来恢复activity状态是不太常见的,而是在onStart(),因为系统会在创建activity与从停止状态重启activity时都会调用onStart().(这个地方的意思应该是说你在onStop里面做了哪些清除的操作就应该在onStart里面重新把那些清除掉的资源重新创建出来)

对于这些回调方法,执行的内容也会有存在一些争议,具体还得看自己的项目再去具体实现。官方也有说明:
根据你的activity的复杂度,也许不需要实现所有的生命周期方法。然而,需要知道每一个方法的功能并确保你的app能够像用户期望的那样执行。如何实现一个符合用户期待的app,你需要注意下面几点:

  • 当使用你的app的时候,不会因为有来电通话或者切换到其他app而导致程序崩溃。
  • 当用户没有激活某个组件的时候不要消耗宝贵的系统资源。
  • 当离开你的app并且一段时间后返回,不要丢失用户的使用进度。
  • 当设备发送屏幕旋转的时候,不会崩溃或者丢失用户的使用进度。

总结

以上是正常情况下Activity生命周期,主要要明白回调方法调用的顺序,才能很好的理解与实践。然而也有异常情况下,生命周期的过程则有不同。在下一篇再进行介绍,Activity的生命周期详细分析(二)
如有误,麻烦指出,谢谢!
温故而知新!

主要参考:
https://developer.android.google.cn/develop/index.html
https://developer.android.google.cn/training/index.html
http://hukai.me/blog/archives/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值