Activity的生命周期详述

来源:互联网 发布:hpv报告单怎么看数据 编辑:程序博客网 时间:2024/05/29 04:48

正常情况下,Activity会经历如下的生命周期:

onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()


onPause():当当前Activity被半遮挡,比如当前Activity上弹出了一个弹窗,则会调用该Activity的onPause()方法;

onStop():  当前Activity被完全遮盖的时候,就会调用该方法,比如当当前Activity中开启一个Activity,被完全遮盖,Activity会依次调用onPause(),onStop()方法


正常的生命周期需要注意:

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

(2)当用户打开一个新的Activity或者切换到桌面,回调:onPause() -> onStop(),不过当弹出的Activity采用了透明主题,或者弹出的是一个Dialog,原来的Activity没有被完全遮盖,那么原来Activity只会调用onPause()方法;

(3)当用户再次回到原来的Activity时,回调:onRestart() -> onStart() -> onResume();

(4)当用户按下BACK键时,Activity调用: onPause() -> onStop() -> onDestroy();


注意的一个问题:

ActivityA为当前Activity,用户打开了一个新的ActivityB,那么ActivityB的onResume()和ActivityA的onPause()哪个先执行呢?


ActivityManagerService会维持一个ActivityStack,负责栈内Activity的维护,其中ActivityStack中有一段源码的注释:

// we need to start pausing the current activity// so the top one can be resumed....


这说明在启动新的Activity之前,Stack顶部的Activity会首先被onPause(),新的Activity才会被启动,我们利用两个Activity打印的信息:

在FirstActivity中打开SecondActivity:

FirstActivity -> onPause()SecondActivity -> onCreate()SecondActivity -> onStart()SecondActivity -> onResume()FirstActivity -> onStop()


异常情况下Activity的生命周期:

情景一:系统配置发生改变导致Activity被Destroy后重新Create

情景二:系统资源内存不足,导致优先级低的Activity被回收

当Activity是竖屏,且没有对其进行任何设置,那么默认的当Activity被横屏之后,Activity会首先被Destroy,然后重新创建:

Activity: onSaveInstanceState() -> onDestroy() -->> onCreate() -> onRestoreInstanceState()

    

    当系统配置发生改变的时候,Activity会被销毁,会调用Activity的onPause(), onStop() , onDestroy()方法,同时异常情况下,Activity在销毁之前,会调用Activity的onSaveInstanceState()方法,该方法的调用时机在onStop()之前,但是和onPause()方法没有明确的时序关系,需要注意的是,onSaveInstanceState()方法只会在Activity异常销毁的时候被调用,在Activity正常销毁的情况下是不会调用此方法的。异常情况下,Activity再次被创建时,会调用onRestoreInstanceState()方法,在此方法中会传递一个Bundle对象,这个Bundle对象中保存了Activity异常销毁时调用onSaveInstanceState()的时候保存在Bundle中的所有参数,而onSaveInstanceState()中保存的Bundle会同时传递给onCreate()和onRestoreInstanceState()两个方法,onRestoreInstanceState()方法的调用时机在onStart()之后。

    开发者可以利用onSaveInstanceState(),onRestoreInstanceState()和onCreate()方法来恢复一些必要的数据,系统同时也利用onSaveInstanceState()和onRestoreInstanceState()方法恢复一些数据,比如TextView中的内容,ListView滚动的位置等,可以查看对应的View的源码,来查看该View会恢复哪些数据,以TextView为例:

@Override    public Parcelable onSaveInstanceState() {        Parcelable superState = super.onSaveInstanceState();        // Save state if we are forced to        boolean save = mFreezesText;        int start = 0;        int end = 0;        if (mText != null) {            start = getSelectionStart();            end = getSelectionEnd();            if (start >= 0 || end >= 0) {                // Or save state if there is a selection                save = true;            }        }        if (save) {            SavedState ss = new SavedState(superState);            // XXX Should also save the current scroll position!            ss.selStart = start;            ss.selEnd = end;            if (mText instanceof Spanned) {                /*                 * Calling setText() strips off any ChangeWatchers;                 * strip them now to avoid leaking references.                 * But do it to a copy so that if there are any                 * further changes to the text of this view, it                 * won't get into an inconsistent state.                 */                Spannable sp = new SpannableString(mText);                for (ChangeWatcher cw : sp.getSpans(0, sp.length(), ChangeWatcher.class)) {                    sp.removeSpan(cw);                }                SuggestionSpan[] suggestionSpans = sp.getSpans(0, sp.length(), SuggestionSpan.class);                for (int i = 0; i < suggestionSpans.length; i++) {                    int flags = suggestionSpans[i].getFlags();                    if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0                            && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {                        sp.removeSpan(suggestionSpans[i]);                    }                }                sp.removeSpan(mSuggestionRangeSpan);                ss.text = sp;            } else {                ss.text = mText.toString();            }            if (isFocused() && start >= 0 && end >= 0) {                ss.frozenWithFocus = true;            }            ss.error = mError;            return ss;        }        return superState;    }

从上面的源码可以看到,TextView保存了输入内容,利用Spannable以富文本方式保存。


Activity被意外回收的生命周期: 

onPause() -> onSaveInstanceState() -> onStop() -> onDestroy()


我们利用onSaveInstanceState()存储数据:

@Overrideprotected void onSaveInstanceState(Bundle outState){super.onSaveInstanceState(outState);outState.putString("account", "mxd_hust");}

在Activity被重新创建时,可以在onCreate()和onRestoreInstanceState()中获得在onSaveInstanceState()中存储的数据:

@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if (savedInstanceState != null){String account = savedInstanceState.getString("account", "--");}}

或者从onRestoreInstanceState()中获取:

@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState){super.onRestoreInstanceState(savedInstanceState);String account = savedInstanceState.getString("account", "--");}


我们知道,当系统配置发生改变的时候,Activity会被重新创建,通过为Activity配置configChanges属性,可以避免Activity的重构,configChanges属性内容很多,为了让某一项内容改变的时候Activity不发生重构,那么可以通过为该Activity的configChanges添加这一项属性内容,比如我们不想让Activity在屏幕横竖屏切换时发生重构,则设置:

android:configChanges="orientation"

多个属性内容使用|分割,比如:

android:configChanges="orientation|keyboardHidden"

下表为Activity的configChanges属性的内容及其含义:

属性内容含义mccSIM卡唯一标识中的国家代号,由三位数字组成,中国是460,当这一项发生改变mncSIM卡唯一标识中的运营商代号,由两位数字组成中国移动TD系统为00,中国联通为01,中国电信为03,此项发生改变locale设备的本地位置发生了改变,一般指系统语言发生改变keyboard键盘类型发生改变,比如用户使用了外接键盘keyboardHidden键盘的可访问性发生了改变,比如用户调出了键盘screenLayout屏幕布局发生了改变,比如用户外接了一个显示器uiMode用户界面模式发生了改变,比如变为了夜间模式(API8新添加的夜间模式)orientation屏幕横竖屏的切换screenSize当屏幕尺寸发生改变,当旋转设备屏幕时,屏幕尺寸也会发生改变,这个属性内容和编译环境有关,
当编译的minSdkVersion和targetSdkVersion低于13时此属性内容不会导致Activity重建,否则会导致Activity重建(API13中新添加)
smallestScreenSize设备屏幕的物理尺寸发生变化,比如当用户切换成外部显示器,同样的smallestScreenSize是在API13新添加的内容,
在minSdkVersion和targetSdkVersion大于13时,才会导致Activity重构
layoutDirection当Activity的布局发生改变,用的很少













在AndroidManifest.xml文件中设置configChanges属性:


<activity      android:name=".MainActivity"      android:configChanges="orientation|keyboard"      android:label="@string/app_name" >      <intent-filter>           <action android:name="android.intent.action.MAIN" />           <category android:name="android.intent.category.LAUNCHER" />      </intent-filter></activity>

此时,设置了Activity的configChanges属性之后,Activity就不会再被重构,onSaveInstanceState()和onRestoreInstanceState()方法也不会被调用,取而代之的是调用onConfigurationChanged()方法:

@Overridepublic void onConfigurationChanged(Configuration newConfig){super.onConfigurationChanged(newConfig);Log.v(LOG, "MainActivity: " + newConfig.orientation);}


0 0
原创粉丝点击