Android Activity的生命周期详解

Activity是由Activity栈进管理,当来到一个新的Activity后,此Activity将被加入到Activity栈顶,以前的Activity位于此Activity底部。Acitivity通常意义上有四种状态:java

1.当Activity位于栈顶时,此时正好处于屏幕最前方,此时处于运行状态浏览器

2.当Activity失去了焦点但仍然对用于可见(如栈顶的Activity是透明的或者栈顶Activity并非铺满整个手机屏幕),此时处于暂停状态网络

3.当Activity被其余Activity彻底遮挡,此时此Activity对用户不可见,此时处于中止状态ide

4.当Activity因为人为或系统缘由(如低内存等)被销毁,此时处于销毁状态函数

在每一个不一样的状态阶段,Adnroid系统对Activity内相应的方法进行了回调。所以,咱们在程序中写Activity时,通常都是继承Activity类并重写相应的回调方法。this

在上图中,Activity有三个关键的循环: spa

1.Activity实例是由系统自动建立,并在不一样的状态期间回调相应的方法。Activity在onCreate()设置全部的“全局”状态,在onDestory()释放全部的资源。一个最简单的完整的Activity生命周期会按照以下顺序回调:onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy。称之为entire lifetime(整个的生命周期)例如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity能够在onCreate()中建立线程,在onDestory()中中止线程。线程

2.当执行onStart回调方法时,Activity开始被用户所见(也就是说,onCreate时用户是看不到此Activity的,那用户看到的是哪一个?固然是此Activity以前的那个Activity),一直到onStop以前,此阶段Activity都是被用户可见,称之为visible lifetime(可见的生命周期)尽管有可能不在前台,不能和用户交互。在这两个接口之间,须要保持显示给用户的UI数据和资源等,例如:能够在onStart中注册一个IntentReceiver来监听数据变化致使UI的变更,当再也不须要显示时候,能够在onStop()中注销它。onStart(),onStop()均可以被屡次调用,由于Activity随时能够在可见和隐藏之间转换。code

3.当执行到onResume回调方法时,Activity能够响应用户交互,一直到onPause方法以前,该Activity处于全部 Activity的最前面,和用户进行交互。此阶段Activity称之为foreground lifetime(前台的生命周期)Activity能够常常性地在resumed和paused状态之间切换,例如:当设备准备休眠时,当一个 Activity处理结果被分发时,当一个新的Intent被分发时。因此在这些接口方法中的代码应该属于很是轻量级的。orm

须要注意一下几点:

在实际应用场景中,假设A Activity位于栈顶,此时用户操做,从A Activity跳转到B Activity。那么对AB来讲,具体会回调哪些生命周期中的方法呢?回调方法的具体回调顺序又是怎么样的呢?

开始时,A被实例化,执行的回调有A:onCreate -> A:onStart -> A:onResume。

当用户点击A中按钮来到B时,假设B所有遮挡住了A,将依次执行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop。

此时若是点击Back键,将依次执行B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。

至此,Activity栈中只有A。在Android中,有两个按键在影响Activity生命周期这块须要格外区分下,即Back键和Home键。咱们先直接看下实验结果:

此时若是按下Back键,系统返回到桌面,并依次执行A:onPause -> A:onStop -> A:onDestroy。

此时若是按下Home键(非长按),系统返回到桌面,并依次执行A:onPause -> A:onStop。因而可知,Back键和Home键主要区别在因而否会执行onDestroy。

此时若是长按Home键,不一样手机可能弹出不一样内容,Activity生命周期未发生变化(由小米2s测的,不知道其余手机是否会对Activity生命周期有影响)。

因为Android自己的特性,使得如今很多应用都没有直接退出应用程序的功能,按照通常的逻辑,当Activity栈中有且只有一个Activity时,当按下Back键此Activity会执行onDestroy,那么下次点击此应用程图标将从从新启动,所以,当前很多应用程序都是采起如Home键的效果,当点击了Back键,系统返回到桌面,而后点击应用程序图标,直接回到以前的Activity界面,这种效果是怎么实现的呢?

经过重写按下Back键的回调函数,转成Home键的效果便可。

@Override
public void onBackPressed() {
    Intent home = new Intent(Intent.ACTION_MAIN);
    home.addCategory(Intent.CATEGORY_HOME);
    startActivity(home);
}

固然,此种方式经过Home键效果强行影响到Back键对Activity生命周期的影响。注意,此方法只是针对按Back键须要退回到桌面时的Activity且达到Home效果才重写。

或者,为达到此类效果,Activity实际上提供了直接的方法。

activity.moveTaskToBack(true);

moveTaskToBack()此方法直接将当前Activity所在的Task移到后台,同时保留activity顺序和状态。


在以前的项目开发过程当中,当时遇到一个很奇怪的问题:手机上的“开发者选项”中有一个“不保留活动”的设置,当开启此设置,手机上的设置提示是“用户离开后即销毁每一个活动”,开启后,对于其余的应用程序是从A Acticity到B Activity,而后Back键回到A,此时,其余应用程序只是先白屏(有可能黑屏等,取决于主题设置)一下,而后A开始可见,可是个人应用程序中出现的一个结果倒是直接返回到了桌面。一开始百思不得其解。最后终于定位出问题。首先,咱们须要明确开启此设置项后对Activity生命周期的影响。开启此设置项后,当A到B时,假设B所有遮挡住了A,将依次执行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop -> A:onDestroy。是的,A在系统本来的生命周期回调中增长了onDestroy。此即“用户离开后即销毁每一个活动”的含义。但此时须要注意的是,只要没有认为的调用A的finish()方法,虽然A执行了onDestroy,但Activity栈中依然保留有A,此时B处于栈顶。那么在B中按Back键回到A时,将依次执行:B:onPause -> A:onCreate -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。没错,A从onCreate开始执行了。此处也就解释了为何A可能会出现白屏(或黑屏等)一下的缘由了。

那么为何个人应用程序会跟其余应用程序出现不同呢?最后定为出问题在于当时个人应用程序中为了作到彻底退出应用程序效果,专门使用了一个Activity栈去维护Activity(当时是借鉴了网上的此类实现方案,如今想一想,实在不必,且不说Android自己特性决定了不必经过如此方法去达到退出效果,仅仅是此方法自己也存在很大的问题,如今在网上依然能见到有很多文章说到应用程序退出可使用此方法,哎。。),在onCreate中入栈,onDestroy出栈,调用了以下方法:

// 结束Activity&从堆栈中移除
AppManager.getAppManager().finishActivity(this);

其中,AppManager中finishActivity函数具体定义是:

/**
 * 结束指定的Activity
 */
public void finishActivity(Activity activity) {
    if (activity != null) {
        activityStack.remove(activity);
        activity.finish();
        activity = null;
    }
}

至此,相信你们应该看出问题的所在了吧。

没错,问题在于执行了activity的finish()方法!! activity的finish()方法至少有两个层面含义,1.将此Activity从Activity栈中移除,2.调用了此Activity的onDestroy方法。对于不开启“不保留活动”的设置项,实际上也没什么影响,可是一旦开启此设置,问题显露无疑。开启此此设置后,正常状况下离开A,即便执行了A的onDestroy,Activity栈中仍是有A的,可是我这样写后,finish()方法一执行,Activity栈中就没有A了,所以,当点击Back键时,Activity栈中已经没有此应用的任何Activity了,直接来到了手机桌面。

可能,有些人会说,我就是要经过此种方法想去彻底退出应用程序,同时但愿本身的Activity栈和系统中Activity栈保持一致,怎么办呢?

在此,能够经过以下改写去实现:

/**
* 结束指定的Activity
 */
public void finishActivity(Activity activity) {
    if (activity != null) {
    // 为与系统Activity栈保持一致,且考虑到手机设置项里的"不保留活动"选项引发的Activity生命周期调用onDestroy()方法所带来的问题,此处须要做出以下修正
    if(activity.isFinishing()){
        activityStack.remove(activity);
        //activity.finish();
        activity = null;
    }
    }
}

下面经过一个例子来介绍:

public class ActivityDemo extends Activity {  
    private static final String TAG = "ActivityDemo";  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        Log.e(TAG, "start onCreate~~~");  
    }  
    @Override  
    protected void onStart() {  
        super.onStart();  
        Log.e(TAG, "start onStart~~~");  
    }  
    @Override  
    protected void onRestart() {  
        super.onRestart();  
        Log.e(TAG, "start onRestart~~~");  
    }  
    @Override  
    protected void onResume() {  
        super.onResume();  
        Log.e(TAG, "start onResume~~~");  
    }  
    @Override  
    protected void onPause() {  
        super.onPause();  
        Log.e(TAG, "start onPause~~~");  
    }  
    @Override  
    protected void onStop() {  
        super.onStop();  
        Log.e(TAG, "start onStop~~~");  
    }  
    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        Log.e(TAG, "start onDestroy~~~");  
    }  
}

咱们打开应用时前后执行了onCreate()->onStart()->onResume()三个方法,看一下LogCat视窗以下:

当咱们按BACK键时,咱们这个应用程序将结束,这时候咱们将前后调用onPause()->onStop()->onDestory()三个方法,以下图所示:

当咱们打开应用程序时,好比浏览器,我正在浏览NBA新闻,看到一半时,我忽然想听歌,这时候咱们会选择按HOME键,而后去打开音乐应用程序,而当咱们按HOME的时候,Activity前后执行了onPause()->onStop()这两个方法,这时候应用程序并无销毁。以下图所示:

而当咱们再次启动ActivityDemo应用程序时,则前后分别执行了onRestart()->onStart()->onResume()三个方法,以下图所示:

这里咱们会引出一个问题,当咱们按HOME键,而后再进入ActivityDemo应用时,咱们的应用的状态应该是和按HOME键以前的状态是同样的,一样为了方便理解,在这里我将ActivityDemo的代码做一些修改,就是增长一个EditText。而后再次运行ActivityDemo程序,在EditText里输入如"Frankie"字符串(以下图:)

这时候,你们能够按一下HOME键,而后再次启动ActivityDemo应用程序,这时候EditText里并无咱们输入的"Frankie"字样,以下图:

这显然不能称得一个合格的应用程序,因此咱们须要在Activity几个方法里本身实现,修改ActivityDemo.java代码以下:

public class ActivityDemo extends Activity {  
     private static final String TAG = "ActivityDemo";  
     private EditText mEditText;  
     //定义一个String 类型用来存取咱们EditText输入的值  
     private String mString;  
     public void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.main);  
         mEditText = (EditText)findViewById(R.id.editText);  
         Log.e(TAG, "start onCreate~~~");  
     }  
     @Override  
     protected void onStart() {  
         super.onStart();  
         Log.e(TAG, "start onStart~~~");  
     }  
     //当按HOME键时,而后再次启动应用时,咱们要恢复先前状态  
     @Override  
     protected void onRestart() {  
         super.onRestart();  
         mEditText.setText(mString);  
         Log.e(TAG, "start onRestart~~~");  
     }   
     @Override  
     protected void onResume() {  
         super.onResume();  
         Log.e(TAG, "start onResume~~~");  
     }  
     //当咱们按HOME键时,我在onPause方法里,将输入的值赋给mString  
     @Override  
     protected void onPause() {  
         super.onPause();  
         mString = mEditText.getText().toString();  
         Log.e(TAG, "start onPause~~~");  
     }   
     @Override  
     protected void onStop() {  
         super.onStop();  
         Log.e(TAG, "start onStop~~~");  
     }  
       
     @Override  
     protected void onDestroy() {  
         super.onDestroy();  
         Log.e(TAG, "start onDestroy~~~");  
     }  
 }

从新运行ActivityDemo程序,重复第五步操做,当咱们按HOME键时,再次启动应用程序时,EditText里有上次输入的"Frankie"字样,以下图如示:

OK,大功基本告成,这时候你们能够在回上面看一下Activity生命周期图,我想你们应该彻底了解了Activity的生命周期了,不知道你了解了没?

最后再用一个实际的例子来讲明Activity的各个生命周期。假设有一个程序由2个Activity A和B组成,A是这个程序的启动界面。当用户启动程序时,Process和默认的Task分别被建立,接着A被压入到当前的Task中,依次执行了 onCreate, onStart, onResume事件被呈现给了用户;此时用户选择A中的某个功能开启界面B,界面B被压入当前Task遮盖住了A,A的onPause事件执行,B的 onCreate, onStart, onResume事件执行,呈现了界面B给用户;用户在界面B操做完成后,使用Back键回到界面A,界面B再也不可见,界面B的onPause, onStop, onDestroy执行,A的onResume事件被执行,呈现界面A给用户。此时忽然来电,界面A的onPause事件被执行,电话接听界面被呈现给用户,用户接听完电话后,又按了Home键回到桌面,打开另外一个程序“联系人”,添加了联系人信息又作了一些其余的操做,此时界面A再也不可见,其 onStop事件被执行,但并无被销毁。此后用户从新从菜单中点击了咱们的程序,因为A和其所在的进程和Task并无被销毁,A的onRestart 和onStart事件被执行,接着A的onResume事件被执行,A又被呈现给了用户。用户此次使用完后,按Back键返回到桌面,A的 onPause, onStop被执行,随后A的onDestroy被执行,因为当前Task中已经没有任何Activity,A所在的Process的重要程度被降到很低,很快A所在的Process被系统结束。

补充一点,当前Activity产生事件弹出ToastAlertDialog的时候Activity的生命周期是不会有改变,即不会触发onPause()等事件

相关文章
相关标签/搜索