天天看點

activity 生命周期_5 道刁鑽的 Activity 生命周期面試題

今天我們一起來看五道 Activity 生命周期的面試題,相信看完之後面試官再問到相關的問題,你就能胸有成竹了。

A Activity 打開 B Activity 時都有哪些生命周期回調。

這道題相信很多同學都有遇到過,簡單 A.onPause -> B.onCrete -> B.onStart -> B.onResume -> A.onStop . Naive ! 這樣回答隻是及格,因為僅在 B Activity 的 launchMode 為 standard 或者 B Activity 沒有可複用的執行個體時是這樣的。

當 B Activity 的 launchMode 為 singleTop 且 B Activity 已經在棧頂時(一些特殊情況如通知欄點選、連點),此時隻有 B 頁面自己有生命周期變化: B.onPause -> B.onNewIntent -> B.onResume

當 B Activity 的 launchMode 為 singleInstance ,singleTask 且對應的 B Activity 有可複用的執行個體時,生命周期回調是這樣的: A.onPause -> B.onNewIntent -> B.onRestart -> B.onStart -> B.onResume -> A.onStop -> ( 如果 A 被移出棧的話還有一個 A.onDestory)

把幾種情況都回答出來就能加分啦,同時也要做好聊 launchMode 的準備。

彈出 Dialog 對生命周期有什麼影響

我們知道,生命周期回調都是 AMS 通過 Binder 通知應用程序調用的;而彈出 Dialog、Toast、PopupWindow 本質上都直接是通過 WindowManager.addView() 顯示的(沒有經過 AMS),是以不會對生命周期有任何影響。

如果是啟動一個 Theme 為 Dialog 的 Activity , 則生命周期為: A.onPause -> B.onCrete -> B.onStart -> B.onResume 注意這邊沒有前一個 Activity 不會回調 onStop,因為隻有在 Activity 切到背景不可見才會回調 onStop;而彈出 Dialog 主題的 Activity 時前一個頁面還是可見的,隻是失去了焦點而已是以僅有 onPause 回調。

Activity 在 onResume 之後才顯示的原因是什麼

雖然我們設定 Activity 的布局一般都是在 onCreate 方法裡調用 setContentView 。裡面是直接調用 window 的 setContentView,建立一個 DecorView 用來包住我們建立的布局。詳情如下:

PhoneWindow.java
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();
    } 
    ...
    // 加載布局,添加到 mContentParent
    // mContentParent 又是 DecorView 的一個子布局  
    mLayoutInflater.inflate(layoutResID, mContentParent);
}
           

然而這一步隻是加載好了布局,生成一個 ViewTree , 具體怎麼把 ViewTree 顯示出來,答案就在下面:

ActivityThread.java
public void handleResumeActivity(...){
    // onResume 回調
    ActivityClientRecord r = performResumeActivity(...)
    final Activity a = r.activity;
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        ViewManager wm = a.getWindowManager();
        wm.addView(decor, l);// 重點
    }
}
           

WindowManager 的 addView 方法最終将 DecorView 添加到 WMS ,實作繪制到螢幕、接收觸屏事件。具體的調用鍊如下:

WindowManagerImpl.addView
-> WindowManagerGlobal.addView
-> ViewRootImpl.setView     
-> ViewRootImpl.requestLayout() // 執行 View 的繪制流程
   // 通過 Binder 調用 WMS ,WMS 會添加一個 Window 相關的對象
   // 應用端通過 mWindowSession 調用 WMS
   // WMS 通過 mWindow (一個 Binder 對象) 調用應用端  
   mWindowSession.addToDisplay(mWindow)
           

綜上,在 onResume 回調之後,會建立一個 ViewRootImpl ,有了它之後應用端就可以和 WMS 進行雙向調用了。同時也是通過 ViewRootImpl 從 WMS 申請 Surface 來繪制 ViewTree 。

onActivityResult 在哪兩個生命周期之間回調

onActivityResult 不屬于 Activity 的生命周期,一般被問到這個問題時大家都會懵逼。其實答案很簡單,onActivityResult 方法的注釋中就寫着答案:

You will receive this call immediately before onResume() when your activity is re-starting.

跟一下代碼(TransactionExecutor.execute 有興趣的可以自己打斷點跟一下),會發現 onActivityResult 回調先于該 Activity 的所有生命周期回調,從 B Activity 傳回 A Activity 的生命周期調用為:

B.onPause -> A.onActivityResult -> A.onRestart -> A.onStart -> A.onResume

onCreate 方法裡寫死循環會 ANR 嗎

ANR 的四種場景:

  1. Service TimeOut: service 未在規定時間執行完成: 前台服務 20s,背景 200s
  2. BroadCastQueue TimeOut: 未在規定時間内未處理完廣播:前台廣播 10s 内, 背景 60s 内
  3. ContentProvider TimeOut: publish 在 10s 内沒有完成
  4. Input Dispatching timeout: 5s 内未響應鍵盤輸入、觸摸螢幕等事件

我們可以看到,Activity 的生命周期回調的阻塞并不在觸發 ANR 的場景裡面,是以并不會直接觸發 ANR。隻不過死循環阻塞了主線程,如果系統再有上述的四種事件發生,就無法在相應的時間内處理進而觸發 ANR。

總結

Activity 的生命周期很基礎而且也很重要,這也是面試常問的原因。相關的面試題可以涉及到 framework 的一些知識,平常在處理一些問題的時候最好不要隻是打下日志看下結果,多鑽進去源碼看看,才能有更多收獲,也記得更牢。

文章首發于公衆号:“Android 面試官”,未經授權請勿轉載。

activity 生命周期_5 道刁鑽的 Activity 生命周期面試題

掃一掃關注公衆号,為你解答 Android 面試的各種問題

繼續閱讀