怎麼理解onStart可見但不可互動

jimuzz發表於2021-03-15

前言

今天朋友遇到一個面試題,分享給大家:

onStart生命週期表示Activity可見,那為什麼不能互動呢?

這個問題看似簡單,但涉及到的面還是比較多的,比如Activity生命週期的理解,程式的理解,以及View繪製的時機。

一起看看吧。

onStart介紹

首先,是關於onStart生命週期的理解。

官網是這麼介紹的:

當 Activity 進入“已開始”狀態時,系統會呼叫此回撥。onStart() 呼叫使 Activity 對使用者可見,因為應用會為 Activity 進入前臺並支援互動做準備。

對使用者可見?

奇怪了,對使用者可見,不就是我們可以看到了嗎,為什麼又不能互動呢?該怎麼理解這個可見呢?

做個小實驗

首先,科普官方定義的兩個狀態。

  • onStart到onStop中間的狀態叫做“已開始”狀態。
  • onResume到onPause中間的狀態叫做“已恢復”狀態。

然後我們做個小實驗,定義ActivityAActivityBActivityB為Dialog主題,ActivityA中點選可以跳轉到B:

    image.setOnClickListener {
        startActivity(Intent(this, ActivityB::class.java))
    }

    <activity android:name=".activity.ActivityB"
        android:theme="@style/Theme.AppCompat.Light.Dialog"
        android:launchMode="standard">
    </activity>

進入ActivityA後,點選按鈕,跳轉到B,這時候A的生命週期走到了onPause,也就是回到了已開始狀態。

這個時候,介面是這個樣子:

ActivityA處在已開始狀態,對使用者可見。

這裡的可見是不是就很好理解了,確實對我們可見了,只不過 不在前臺,不能互動

所以延伸到普通的Activity,這個可見,並不是表示使用者能用肉眼看到了,而是想表達:

Activity已經顯示出來了,但是還不在前臺,所以只是可見,但不可互動。

這個可見狀態是從onStart開始,onStop結束,我們可以分為兩個階段:

  • onStart到onResume。這個階段,Activity被建立,佈局已載入,但是介面還沒繪製,可以說介面都不存在。
  • onPause到onStop。這個階段,就是我們剛才所做的實驗,Activity有介面,只是被新的介面所遮擋,也就是不在前臺。

所以綜合兩個階段,我們把這種Activity被建立或已經顯示出來,但是不在前臺,介於兩者之間的狀態叫做 可見 狀態。

onStart 和 onResume

到此,我們知道了可見的意思,其實也就知道了另外一個問題,也就是為什麼要設計出onStart和onResume這兩種狀態。

  • onStart和onStop,是從Activity是否可見的角度設計的。
  • onResume和onPause,是從Activity是否位於前臺的角度設計的。

所以Activity的生命週期又可以解釋為:

被建立(onCreate)——> 可見(onStart)——> 位於前臺(onResume)——> 可見但不在前臺(onPause)

可見程式

從另外的角度看,這個可見 可以指的是 可見程式
這就涉及到程式的分類。

為了確定在記憶體不足時應該終止哪些程式,Android 會根據每個程式中執行的元件以及這些元件的狀態,將它們放入“重要性層次結構”。這些程式型別包括(按重要性排序):前臺程式,可見程式,服務流程,快取程式

這些程式是什麼意思呢?

  • 前臺程式是使用者目前執行操作所需的程式。比如 正在使用者的互動螢幕上執行一個 Activity(其 onResume() 方法已被呼叫)
  • 可見程式是正在進行使用者當前知曉的任務。比如 正在執行的 Activity 在螢幕上對使用者可見,但不在前臺(其 onPause() 方法已被呼叫)
  • 服務流程包含一個已使用 startService() 方法啟動的 Service。
  • 快取程式是目前不需要的程式。比如 當前不可見的一個或多個 Activity 例項(onStop() 方法已被呼叫並返回)

所以Activity的生命週期又可以通過程式分為:

可見程式(onStart)——> 前臺程式(onResume)——> 可見程式(onPause)——> 快取程式(onStop)

這些程式有什麼用呢?

我們都知道,在Android系統中有很多很多執行中的APP,也就代表了不同的程式。

當記憶體不夠時(達到了某個閾值),系統首先會通過onTrimMemory()回撥方法告訴應用,讓應用自己來處理低記憶體情況下的減少記憶體操作。
這之後,如果記憶體還是很緊張,那麼就會開始對一些程式的殺除,以釋放記憶體。這裡就需要判斷程式的優先順序了,從低優先順序開始按順序終止程式。

所以,程式的分類作用就在這了。優先順序的高低其實就代表了 終止程式的順序,也代表了對使用者的影響程度。

當然實際程式碼中,程式優先順序是有數字表示的,也就是ADJ,而上面說的程式型別都有相應的程式優先順序數字範圍。比如:

public final class ProcessList {
    //可見程式
    static final int VISIBLE_APP_ADJ = 100;

    // 前臺程式
    static final int FOREGROUND_APP_ADJ = 0;

    // 服務程式
    static final int SERVICE_ADJ = 500;

    // 快取程式
    static final int CACHED_APP_MIN_ADJ = 900;

    //...
}

再回到我們的問題上來:

其中,可見程式這裡也出現了可見的概念,給出的解釋是:使用者知曉

當我們點選一個頁面,我們知道這個頁面將要顯示出來,也知道之前的頁面在這個頁面後面。所以這些頁面和程式都是我們所知曉的,只是不在前臺。

所以onStart表示的可見,也可以理解為可見程式,意思是這個Activity所在的程式任務已經被建立並顯示,我們知曉它,只是沒在前臺。

可互動

那麼可以互動到底是發生在什麼階段呢?

之前我們說過,在Activity啟動過程中,呼叫了handleResumeActivity方法。在這個方法中,呼叫了onResume方法和addView方法,完成了View的第一次繪製,並顯示到介面上。

    @Override
    public void handleResumeActivity() {
        //onResume
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        //addView
        if (r.window == null && !a.mFinished && willBeVisible) {
            wm.addView(decor, l);
        }
    }   

所以到onResume,View才被繪製出來,並顯示到前臺。

官網是這麼解釋onResume的:

Activity 會在進入“已恢復”狀態時來到前臺,然後系統呼叫 onResume() 回撥。這是應用與使用者互動的狀態。應用會一直保持這種狀態,直到某些事件發生,讓焦點遠離應用。此類事件包括接到來電、使用者導航到另一個 Activity,或裝置螢幕關閉。

所以可互動狀態應該是在onResume之後,也就是Activity可見並且處於前臺。

小結

總結下:

onStart狀態表示Activity可見,而可見表示的意思是Activity被建立出來了,被使用者所知曉,但是不在前臺,還沒繪製介面,所以無法互動。也可以意指其所在的程式為可見程式。

其可見之意應該和onStop一起使用,即onStartonStop這個階段叫做 可見 階段。

而真正顯示出來可以進行互動 發生在onResume之後,也就是View繪製出來,並處於前臺的時候。

參考

《Android開發藝術探索》
https://juejin.cn/post/6896751245722615815
https://juejin.cn/post/6891911483379482637

拜拜

感謝大家的閱讀,有一起學習的小夥伴可以關注下我的公眾號——碼上積木❤️❤️
每日一個知識點,積少成多,建立知識體系架構。
這裡有一群很好的Android小夥伴,歡迎大家加入~

相關文章