Android基础篇之Activity(二) - Activity生命周期

来源:互联网 发布:sql syntax什么意思 编辑:程序博客网 时间:2024/06/03 20:32

1.为什么要了解Activity生命周期

了解Activity的生命周期的根本目的就是为了设计用户体验更加良好的应用。因为Activity就相当于MVC中的View层,是为了更好的向用户展现数据,并与之交互。了解Activity的生命周期和各回调方法的触发时机,我们可以更好的在合适的地方向用户展现数据(因为每个应用每个Activity的作用不同,所以具体每个回调方法的最佳实践不好把握,但是只要遵循最基本的原则即可),保证数据的完整性和程序的良好运行。

2.生命周期

1.生命周期图解

官方图解

@ljbphoebe

这是官方给出的Activity生命周期图解,和一位名为ljbphoebe博友的图片,接下来我们来详细解释一下每个生命周期回调方法的作用。

2.生命周期回调方法

onCreate()

当启动一个activity的时候第一个被调用的方法,在此回调方法中我们需要调用setContentView为当前Activity设置视图,并且初始化各种控件、设置监听、初始化一些全局的变量等。在Activity的一次生命周期中,onCreate方法只会执行一次。在Paused和Stopped状态下恢复或重启的下,这些控件、监听和全局变量也不会丢失。即便是内存不足,被回收了,再次Recreate的话,又是一次新的生命周期的开始,又会执行onCreate方法。

在onCreate()执行完毕之后会执行onStart()方法。并且在执行完此方法之后不会因为内存不足而回收当前的Activity。

当Activity被第首次加载时执行。我们新启动一个程序的时候其主窗体的onCreate事件就会被执行。如果Activity被销毁后(onDestroy后),再重新加载进Task时,其onCreate事件也会被重新执行。注意这里的参数 savedInstanceState(Bundle类型是一个键值对集合,大家可以看成是.Net中的Dictionary)是一个很有用的设计,由于前面已经说到的手机应用的特殊性,一个Activity很可能被强制交换到后台(交换到后台就是指该窗体不再对用户可见,但实际上又还是存在于某个Task中的,比如一个新的Activity压入了当前的Task从而“遮盖”住了当前的 Activity,或者用户按了Home键回到桌面,又或者其他重要事件发生导致新的Activity出现在当前Activity之上,比如来电界面),而如果此后用户在一段时间内没有重新查看该窗体(Android通过长按Home键可以选择最近运行的6个程序,或者用户直接再次点击程序的运行图标,如果窗体所在的Task和进程没有被系统销毁,则不用重新加载,直接重新显示Task顶部的Activity,这就称之为重新查看某个程序的窗体),该窗体连同其所在的 Task和Process则可能已经被系统自动销毁了,此时如果再次查看该窗体,则要重新执行 onCreate事件初始化窗体。而这个时候我们可能希望用户继续上次打开该窗体时的操作状态进行操作,而不是一切从头开始。例如用户在编辑短信时突然来电,接完电话后用户又去做了一些其他的事情,比如保存来电号码到联系人,而没有立即回到短信编辑界面,导致了短信编辑界面被销毁,当用户重新进入短信程序时他可能希望继续上次的编辑。这种情况我们就可以覆写Activity的void onSaveInstanceState(Bundle outState)事件,通过向outState中写入一些我们需要在窗体销毁前保存的状态或信息,这样在窗体重新执行onCreate的时候,则会通过 savedInstanceState将之前保存的信息传递进来,此时我们就可以有选择的利用这些信息来初始化窗体,而不是一切从头开始。

onStart()

这个方法会在onCreate()方法执行完成之后被调用,也就是视图被初始化之后被调用。调用这个方法的时候我们就可以看到界面了。但是我们还不能获取到界面的焦点,在此方法之后会onRestart()或者onStop()方法。

在activity变为在屏幕上对用户可见时调用。onCreate事件之后执行。或者当前窗体被交换到后台后,在用户重新查看窗体前已经过去了一段时间,窗体已经执行了onStop事件,但是窗体和其所在进程并没有被销毁,用户再次重新查看窗体时会执行onRestart事件,之后会跳过onCreate事件,直接执行窗体的onStart事件。

onRestart()

重新启动activity时调用。该活动仍在栈中,而不是启动新的活动。onStop事件执行后,如果窗体和其所在的进程没有被系统销毁,此时用户又重新查看该窗体,则会执行窗体的onRestart事件,onRestart事件后会跳过窗体的onCreate事件直接执行onStart事件。

onResume()

activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法总是被调用的)。onStart事件之后执行。或者当前窗体被交换到后台后,在用户重新查看窗体时,窗体还没有被销毁,也没有执行过onStop事件(窗体还继续存在于Task中),则会跳过窗体的onCreate和onStart事件,直接执行onResume事件。

onPause()

当Activity失去焦点的时候调用次方,这时候用户不能操作当前Activity,此方法适合做一些持久化的操作。但是启动下一个Activity必须要等到这个方法返回,所以这个方法还不能做耗时操作,因为做了耗时操作会给用户一种切换下一个Activity要等待很长时间,这样的用户不是很好,所有建议在onStop()方法中去完成数据的持久化工作。在此方法之后

activity被暂停或收回cpu和其他资源时调用,该方法用于保存活动状态的,也是保护现场,压栈吧!窗体被交换到后台时执行。

onStop()

Activity进入到Stopped状态之后,它极有可能被系统所回收,在某些极端情况下,系统可能是直接杀死应用程序的进程,而不是调用onDestory方法,所以我们需要在onStop方法中尽可能的释放那些用户暂时不需要使用的资源,防止内存泄露。

尽管onPause在onStop之前执行,但是onPause只适合做一些轻量级的操作,更多的耗时耗资源的操作还是要放在onStop里面,比如说对数据保存,需要用到的数据库操作。因为从Stopped状态重启之后, onStart和onRestart方法都会被执行,所以我们要判断哪些操作分别要放在哪个方法里面 。因为可能在onStop方法里面释放了一些资源,那么我们必须要重启他们,这个时候这些重启的操作放在onStart方法里面就比较好(因为onCreate之后也需要开启这些资源)。那些因为Stopped之后引发的需要单独操作的代码,就可以放在onRestart里面。

onDestroy()

activity被完全从系统内存中移除时调用,该方法被调用可能是因为有人直接调用onFinish()方法或者系统决定停止该活动以释放资源!Activity被销毁的时候执行。在窗体的onStop事件之后,如果没有再次查看该窗体,Activity则会被销毁。确定某些资源是否没有被释放,做一些最终的清理工作,比如在这个Activity的onCreate中开启的某个线程,那么就要在onDestory中确定它是否结束了,如果没有,就结束它。

2.生命周期验证

接下来我们创建个demo来看一下Activity的不同场景下生命周期方法调用顺序。

demo中有两个Activity、分别如下:

MainActivity.java

package com.lyong.testactivity;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;public class MainActivity extends Activity {    // 声明一个Button    private Button btnGoSecond;    private final static String TAG = MainActivity.class.getSimpleName();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Log.i(TAG,"onCreate");        // 初始化Button        btnGoSecond = (Button) findViewById(R.id.btn_go_second);        // 为Button设置点击事件        btnGoSecond.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                // 使用Intent跳转到SecondActivity                Intent intent = new Intent(MainActivity.this,SecondActivity.class);                startActivity(intent);            }        });    }    @Override    protected void onStart() {        super.onStart();        Log.i(TAG, "onStart");    }    @Override    protected void onRestart() {        super.onRestart();        Log.i(TAG, "onRestart");    }    @Override    protected void onResume() {        super.onResume();        Log.i(TAG, "onResume");    }    @Override    protected void onPause() {        super.onPause();        Log.i(TAG, "onPause");    }    @Override    protected void onStop() {        super.onStop();        Log.i(TAG, "onStop");    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.i(TAG, "onDestroy");    }}

SecondActivity.java

package com.lyong.testactivity;import android.app.Activity;import android.os.Bundle;import android.util.Log;public class SecondActivity extends Activity {    private final static String TAG = SecondActivity.class.getSimpleName();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        Log.i(TAG,"onCreate");    }    @Override    protected void onStart() {        super.onStart();        Log.i(TAG, "onStart");    }    @Override    protected void onRestart() {        super.onRestart();        Log.i(TAG, "onRestart");    }    @Override    protected void onResume() {        super.onResume();        Log.i(TAG, "onResume");    }    @Override    protected void onPause() {        super.onPause();        Log.i(TAG, "onPause");    }    @Override    protected void onStop() {        super.onStop();        Log.i(TAG, "onStop");    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.i(TAG, "onDestroy");    }}

场景1.启动应用

在系统桌面上点击应用图标启动应用日志如下:

08-07 16:00:09.665    1802-1802/com.lyong.testactivity I/MainActivity﹕ onCreate08-07 16:00:09.665    1802-1802/com.lyong.testactivity I/MainActivity﹕ onStart08-07 16:00:09.665    1802-1802/com.lyong.testactivity I/MainActivity﹕ onResume

调用顺序为:onCreate -> onStart -> onResume

场景2.启动一个新的Activity

从MainActivity中点击按钮跳转到SecondActivity日志如下:

08-07 16:01:57.235    1802-1802/com.lyong.testactivity I/MainActivity﹕ onPause08-07 16:01:57.265    1802-1802/com.lyong.testactivity I/SecondActivity﹕ onCreate08-07 16:01:57.265    1802-1802/com.lyong.testactivity I/SecondActivity﹕ onStart08-07 16:01:57.265    1802-1802/com.lyong.testactivity I/SecondActivity﹕ onResume08-07 16:01:57.615    1802-1802/com.lyong.testactivity I/MainActivity﹕ onStop

调用顺序为:MainActivity.onPause -> SecondActivity.onCreate -> SecondActivity.onStart -> SecondActivity.onResume ->MainActivity.onStop

从这里我们可以看到在第一个activity的onPause()方法执行完成之后就执行了第二个activity的生命周期方法、当第二个activity创建完成之后才调用的第一个activity的onStop()方法,这也验证了我们上面所描述的,建议在onStop中进行持久化操作。

场景3.回到上一个Activity

接着场景2我们按一下back键得到如下日志:

08-07 16:08:18.265 1802-1802/com.lyong.testactivity I/SecondActivity﹕ onPause
08-07 16:08:18.295 1802-1802/com.lyong.testactivity I/MainActivity﹕ onRestart
08-07 16:08:18.295 1802-1802/com.lyong.testactivity I/MainActivity﹕ onStart
08-07 16:08:18.295 1802-1802/com.lyong.testactivity I/MainActivity﹕ onResume
08-07 16:08:18.645 1802-1802/com.lyong.testactivity I/SecondActivity﹕ onStop
08-07 16:08:18.645 1802-1802/com.lyong.testactivity I/SecondActivity﹕ onDestroy

执行顺序为:SecondActivity.onPause -> MainActivity.onRestart -> MainActivity.onStart -> MainActivity.onResume -> SecondActivity.onStop ->SecondActivity.onDestroy

当我们返回到第一个activity是,首先是暂停第二个activity,然后重新启动第一个activity,重新启动完成之后会停止并销毁第二个activity,这时候第二个activity就从栈中弹出,而第一个activity在栈的定不了。

场景4.接着场景3继续按back键

得到如下日志:

08-07 16:13:42.695    8126-8126/com.lyong.testactivity I/MainActivity﹕ onPause08-07 16:13:43.305    8126-8126/com.lyong.testactivity I/MainActivity﹕ onStop08-07 16:13:43.305    8126-8126/com.lyong.testactivity I/MainActivity﹕ onDestroy

如果按下back键则MainActivity会从栈中弹出,并由系统销毁。大家可以尝试接着场景2按home键,试试!这里就不单独作为一个场景来分析了。

场景5.横竖屏切换

1.竖屏切换为横屏可以得到如下日志:
08-07 16:31:14.635  17686-17686/com.lyong.testactivity I/MainActivity﹕ onPause08-07 16:31:14.635  17686-17686/com.lyong.testactivity I/MainActivity﹕ onStop08-07 16:31:14.635  17686-17686/com.lyong.testactivity I/MainActivity﹕ onDestroy08-07 16:31:14.675  17686-17686/com.lyong.testactivity I/MainActivity﹕ onCreate08-07 16:31:14.675  17686-17686/com.lyong.testactivity I/MainActivity﹕ onStart08-07 16:31:14.675  17686-17686/com.lyong.testactivity I/MainActivity﹕ onResume

这里可以得出一个结论,从竖屏切换为横屏,声明周期会重新执行一遍。

2.横屏切换为竖屏可以得到如下日志:
08-07 16:41:46.995  22062-22062/com.lyong.testactivity I/MainActivity﹕ onPause08-07 16:41:46.995  22062-22062/com.lyong.testactivity I/MainActivity﹕ onStop08-07 16:41:46.995  22062-22062/com.lyong.testactivity I/MainActivity﹕ onDestroy08-07 16:41:47.045  22062-22062/com.lyong.testactivity I/MainActivity﹕ onCreate08-07 16:41:47.045  22062-22062/com.lyong.testactivity I/MainActivity﹕ onStart08-07 16:41:47.045  22062-22062/com.lyong.testactivity I/MainActivity﹕ onResume

同样的,横屏切换为竖屏也会重新执行一遍生命周期方法,设置 android:configChanges=”orientation” 和不设置这个属性,这两个效果是一样的,activity都是重新创新,在之前很多人总结横屏切换竖屏会执行两次生命周期方法,在现在已经不对了。这点大家要注意哦!

更多关于横竖屏切换的信息可以参考一下这篇文章:
[http://www.cnblogs.com/xiaoQLu/p/3324503.html]

关于生命周期的探讨就到这里了。场景还有很多,大家有兴趣的可以尝试一下。如有不对大家多多指正。

0 0