天天看點

Activity不同情況下生命周期

想要徹底弄清楚Activity在不同情況下的生命周期需要先掌握Activity的一些基礎知識

Activity完整的生命周期如下圖:

Activity不同情況下生命周期

知道了Activity完整的生命周期之後還需要知道Activity的啟動模式。

Activity四種啟動模式:

  • standard:

    預設的啟動模式,每次通過這種模式啟動目标Acitivity,都建立一個新的執行個體,并将該Activity添加到目前棧頂。

  • singleTop:

    隻有當Activity位于棧頂時,系統才不會重新建立目标Activity的執行個體,而是直接複用已有的Activity執行個體。否則建立一個新的執行個體。這種模式經常被用在新聞展示頁,當推送過來一條新聞,跳轉到新聞頁顯示,如果你正在看新聞,就不需要重複的建立這個activity

  • singleTask:

    如果棧中不存在目标Activity時,則建立目标Activity執行個體。

    如果棧中存在目标Activity時,

    (1)已經位于棧頂,此時與singleTop行為相同

    (2)不位于棧頂,系統會使該Activity上面所有的Activity出棧。

  • singleInstance:

    如果棧中不存在目标Activity,系統會建立一個新的任務棧,再建立Activity執行個體,将它加入該棧中

    如果棧中存在該Activity,無論哪個應用程式調用,都不會建立新的Activity

舉例

假設有兩個Activity A、B

  1. standard模式

    當A啟動到從A跳轉到B的生命周期

    A啟動時:onCreate -> onStart -> onResume

    從A跳轉到B時:A.onPause -> B.onCreate -> onStart -> onResume -> A.onStop

    按back鍵傳回時:B.onPause -> A.onReStart -> onStart -> onResume -> B.onStop -> onDestroy

  2. singleTop模式

    設定A為singleTop,啟動A,從A跳A,就是在棧頂時會不會建立A的執行個體

    A啟動時:onCreate -> onStart -> onResume

    從A跳A時:onPause -> onResume

    按back鍵傳回時:onPause -> onStop -> onDestroy

    可以看到并沒有重新建立A的執行個體,隻是執行了onPause 和onResume

  3. singleTask模式

    設定A為singleTask,啟動A,從A跳B,再從B跳A

    A啟動時:onCreate -> onStart -> onResume

    從A跳轉到B時:A.onPause -> B.onCreate -> onStart -> onResume -> A.onStop

    從B跳轉到A時:B.onPause -> A.onReStart -> onStart -> onResume -> B.onStop -> onDestroy

    可以看到當A在棧中存在時,再次跳轉不會建立A的執行個體并使A上面的B出棧

  4. singleInstance模式

    為 singleInstance 模式時,activity獨占一個task,現在有以下三個activity: Act1、Act2、Act3,其中Acti2 為 singleInstance 模式。它們之間的跳轉關系為: Act1 – Act2 – Act3 ,現在在Act3中按下傳回鍵,由于Act2位于一個獨立的task中,它不屬于Act3的上下文activity,是以此時将直接傳回到Act1,Act1再按下傳回鍵時到Act2,這就是singleInstance模式。

看完四種模式,這裡會有疑問:

為什麼要先執行A的onPause方法,再執行B的生命周期方法?

為什麼不是執行完A的onStop方法之後再執行B的生命周期方法?

首先來看第一個問題,假如A正在播放一段音樂,如果先執行B的生命周期,再執行A的onPause方法,就會出現B已經顯示出來,A中的音樂還在播放的異常情況。而如果先執行了A的onPause方法,我們就可以在其中執行一些操作來暫停音樂的播放。原本onPause方法的設計職責即使如此。

對于第二個問題,由于Activity的可見生命周期是onStart()到onStop(),假如先執行A的onPause()和onStop(),再執行B的生命周期,每次切換的時候就會出現黑屏的情況,這種切換效果顯然是不優雅的。

注:

  • 建議在onCreate()中調用setContentView()、findViewById()
  • 建議在onResume()中打開獨占裝置(比如相機)、開啟動畫等
  • 建議在onPause()中執行關閉獨占裝置、停止動畫等比較耗CPU的操作,但不要執行比較耗時的操作,底層執行Activity的onPause()時,有一定的時間限制的,當ActivityManagerService通知應用程序暫停指定的Activity時,如果對應的onPause()在500ms内還沒有執行完,ActivityManagerService就會強制關閉這個Activity。
  • onStop()中可以執行一些比較耗時的操作,這是在背景執行是以也不影響使用者的體驗

附:

伴随着activity常用的除了生命周期還有兩個方法,onSaveInstanceState 和 onNewIntent

1.onSaveInstanceState

我們都知道不同的手機,記憶體不同,系統在記憶體不足的時候很有可能就會把你APP中不再棧頂的activity給回收掉。如果這個activity無關緊要那就啥也不說了,但是就怕它對你來說很重要。這個時候你不對它進行保護措施的話,你就等着哭吧。比如你打開了A,A是一個注冊類activity。然後你填寫了一堆資訊後,傳回桌面去看了一條短信,或者接了一個電話,等你再打開這個的時候你發現裡面填寫的東西都不見了,這個時候你想不想一巴掌拍死這個開發人員?

是以呢onsaveinstancestate()就可以閃亮登場了,雖然你也可以使用其他儲存機制去處理,但是對于這種情況,onsaveinstancestate()依然是最佳的選擇。onsaveinstancestate()方法有的同學有可能沒見過 但是savedinstancestate相必都見過,就是在oncreate()方法的那個括号裡面,savedinstancestate是一個bundle類型的參數,bundle有很多儲存資料的方法這個你想必是知道的吧,對我們就是利用這個去儲存資料。onsaveinstancestate()回調方法會保證一定在activity被回收之前調用

onSaveInstanceState方法會在什麼時候被執行,有這麼幾種情況:

  • 當使用者按下HOME鍵時。
  • 長按HOME鍵,選擇運作其他的程式時。
  • 按下電源按鍵(關閉螢幕顯示)時。
  • 從activity A中啟動一個新的activity時。
  • 螢幕方向切換時,例如從豎屏切換到橫屏時。

當按下HOME鍵或者鎖屏時,會執行onPause -> onSaveInstanceState -> onStop

當從activity A跳轉到 B 時,A.onPause -> B.onCreate -> onStart -> onResume -> A.onSaveInstanceState -> A.onStop

使用:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_one);
        if (savedInstanceState != null) {
            String oldString = savedInstanceState.getString("Activity");
            Log.e(TAG,"oldString="+oldString);
        }
        Log.e(TAG,"onCreate");
    }

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG,"onSaveInstanceState");
        String string = "activity 被系統回收了怎麼辦?";
        outState.putString("Activity", string);
    }
           

2.onNewIntent

如果activity設定為singleTask或者signleTop模式【當調用startActivity方法時,這兩種模式不會重新建立activity,隻會調用onNewIntent方法,當然任務棧中沒有銷毀該activity的情況下】,再向activity傳值時,就可以利用onNewIntent

執行順序:onNewIntent -> onReStart -> onStart -> onResume

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.e(TAG,"onNewIntent");
        setIntent(intent);
        String msg = getIntent().getExtras().getString("msg");
        Log.e(TAG,"msg="+msg);
    }

//另一個activity中發送
 Intent intent = new Intent(this,OneActivity.class);
 intent.putExtra("msg","傳值過來");
 startActivity(intent);
           

繼續閱讀