android基礎學習-android篇day17-Activity的生命週期(轉)

發條魚發表於2018-09-23

轉載:https://www.cnblogs.com/lwbqqyumidi/p/3769113.html

轉載:https://www.cnblogs.com/nylcy/p/6500832.html

一、Activity的基本概念

  Activity是Android的四大元件之一,它是一種可以包含使用者介面的元件,主要用於和使用者進行互動,比如打電話,照相,傳送郵件,或者顯示一個地圖!Activity用於顯示使用者介面,使用者通過Activity互動完成相關操作 , 一個App允許有多個Activity。

二、Activity的生命週期

  Activity生命週期是每一個Android開發者都必須掌握的,當我們深入理解活動的生命週期之後,就可以寫出更加連貫流暢的程式,讓我們的程式擁有更好的使用者體驗

 2.1、Activity的生命週期圖

  先上一張從圖吧,圖片看上去一目瞭然。圖片來源(http://www.runoob.com/w3cnote/android-tutorial-activity.html)

  

2.2、Activity的四種狀態

  每個Activity在其生命週期中最多可能會有四種狀態。

  • 1.執行狀態

  當一個Activity位於返回棧(關於返回棧的概念下面再介紹)的棧頂時,這時Activity就處於執行狀態,系統會將處於棧頂的Activity顯示給使用者。

  • 2.暫停狀態

  當一個Activity不再處於棧頂位置,但仍然可見,這時Activity就進入了暫停狀態。初學者可能會有這樣的疑問,既然Activity都已經不在棧頂了,怎麼會還可見呢,這是因為並不是每一個Activity都會佔滿整個螢幕的,比如對話方塊形式的Activity只會佔用螢幕中間的部分割槽域。

  • 3.停止狀態

   當一個Activity不再處於棧頂位置,並且完全不可見的時候,就進入了停止狀態。

  • 4.銷燬狀態

  當一個Activity從返回棧中移除後就變成了銷燬狀態。

2.3、Android返回棧

  Android是使用任務(Task)來管理Activity的,一個任務就是一組存放在棧裡的Activity集合,這個棧被稱作返回棧,棧(堆疊)是一種先進後出的資料結構,這裡順便提一下另一種常見的資料結構:佇列,佇列是一種先進先出的資料結構。

Activity是由Activity棧進管理,每當啟動一個新的Activity後,它會被放入返回棧中,並處於棧頂的位置,之前的Activity位於此Activity底部。每當我們按下Back鍵或呼叫activity的finish()方法去銷燬一個活動時,處於棧頂的Activity會出棧,這時前一個入棧的Activity就會重新處於棧頂的位置。系統總是會顯示處於棧頂的Activity給使用者。

Acitivity一般意義上有四種狀態:

  • 1.當Activity位於棧頂時,此時正好處於螢幕最前方,此時處於執行狀態
  • 2.當Activity失去了焦點但仍然對用於可見(如棧頂的Activity是透明的或者棧頂Activity並不是鋪滿整個手機螢幕),此時處於暫停狀態
  • 3.當Activity被其他Activity完全遮擋,此時此Activity對使用者不可見,此時處於停止狀態
  • 4.當Activity由於人為或系統原因(如低記憶體等)被銷燬,此時處於銷燬狀態

在每個不同的狀態階段,Adnroid系統對Activity內相應的方法進行了回撥。因此,我們在程式中寫Activity時,一般都是繼承Activity類並重寫相應的回撥方法。

 2.4、Activity的生存期

  Activity類中定義了7個回撥方法,覆蓋了Activity生命週期的每一個環節,下面來一一介紹這7個方法

1.onCreate()

  這個方法在每一個Activity類都會有,當我們新建一個Activity類時,一定會重寫父類的onCreate方法,onCreate方法會在Activity第一次被建立時呼叫。我們應該在這個方法中完成Activity的初始化操作,比如說載入佈局,初始化佈局控制元件,繫結按鈕事件等。

2.onStart()

  這個方法在Activity由不可見變為可見時呼叫。

3.onResume()

  這個方法在Activity準備好喝使用者互動的時候呼叫。此時的Activity一定位於返回棧的棧頂,並且處於執行狀態。

4.onPause()

  這個方法在系統準備去啟動或者恢復另一個Activity的時候呼叫。

5.onStop()

  這個方法在Activity完全不可見的時候呼叫。它和onPause()方法的主要區別在於,如果啟動的新Activity是一個對話方塊式的activity,那麼,onPause()方法會得到執行,而onStop()方法並不會執行。

6.onDestory()

  這個方法在Activity被銷燬之前呼叫,之後Activity的狀態將變為銷燬狀態。

7.onRestart()

  這個方法在Activity由停止狀態變為執行狀態之前呼叫,也就是Activity被重新啟動了。

三、體驗Activity的生命週期

1.Activity例項是由系統自動建立,並在不同的狀態期間回撥相應的方法。

一個最簡單的完整的Activity生命週期會按照如下順序回撥:onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy。稱之為entire lifetime。

2.當執行onStart回撥方法時,Activity開始被使用者所見(也就是說,onCreate時使用者是看不到此Activity的,那使用者看到的是哪個?當然是此Activity之前的那個Activity),一直到onStop之前,此階段Activity都是被使用者可見,稱之為visible lifetime。

3.當執行到onResume回撥方法時,Activity可以響應使用者互動,一直到onPause方法之前,此階段Activity稱之為foreground lifetime。

在實際應用場景中,假設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出棧,呼叫瞭如下方法

1 // 結束Activity&從堆疊中移除
2 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;
    }
    }
}

相關文章