Android 視窗是如何建立的?

墨鏡貓發表於2016-12-29

前言

在WmS看來視窗並不是Window類,而是一個View類。WmS收到使用者訊息後,需要把訊息傳送到視窗,View類其實並不能直接接受傳遞過來的訊息,而接受訊息的必須是IWindow類,實現IWindow類的是ViewRoot.W類,每一個W內部都包含了一個View變數。

WmS並不在意該視窗是哪個應用程式的,關心的是活躍視窗,WmS按一定得規則判斷哪個視窗處於活動狀態,然後把使用者訊息給W類,W類再把使用者訊息傳遞給內部View變數,然後再由View物件完成剩下的訊息處理。

窗戶有幾種型別?

Framework定義了三種視窗型別,三種視窗型別的定義在WindowManager類裡面。

  • 應用視窗。應用視窗一般指該視窗對應一個Activity,由於載入Activity是由Ams完成的,所以對於應用程式建立應用類視窗只能在Activity內部完成。
  • 子視窗。子視窗是指該視窗必須要有一個父視窗,父視窗可以是一個應用類視窗也可以是任何其他的視窗。
  • 系統視窗。系統視窗不需要對應任何Activity,也不需要有父視窗。應用程式是沒有辦法建立系統視窗的,只有系統程式可以建立系統視窗。

那麼該怎麼建立應用視窗呢?

1.每個應用類視窗都對應一個Activity物件,所以建立應用類視窗需要建立Activity物件。當AmS要啟動某個Activity時就會通知客戶端程式,每個客戶端程式都對應一個ActivityThread類,所以需要ActivityThread啟動Activity。

啟動某個Activity實際是構造一個Activity物件,使用ClassLoader從程式檔案中裝載指定的Activity對應的Class檔案。

2.建立完成Activity物件後呼叫Activity的attach()方法,attach()的作用就是為剛剛創造好的Activity設定內部變數。

3.為該Activity建立Window物件。

4.給Window物件中的mWindowManager變數賦值。

5.然後就需要給該視窗新增真正的View或者ViewGroup。從performLaunchActivity()呼叫callActivityOnCreate()開始,然後經一系列呼叫到Activity的onCreate()方法,在onCreate()方法中呼叫setContentView()方法實際是呼叫了其對應的Window物件的setContentView()方法。

6.接著會呼叫到PhoneWindow的setContentView,首先呼叫installDecor()為Window類新增視窗裝飾,其實就是標題欄,程式中設定的layout.xml介面被包含在視窗裝飾中,就是視窗內容。視窗裝飾也是ViewGroup,視窗裝飾和它內部的內容加起來就是我們所說的視窗,或者叫做Window介面。

7.把建立的視窗通知WmS,讓WmS把視窗顯示在螢幕上。當Activity準備好後會通知Ams,然後Ams經過一系列呼叫到Activity的makeVisible(),該方法將真正完成把視窗新增進Wms中。

8.在makeVisible方法中,首先獲得該Activity內部的WindowManager物件,然後呼叫該物件的addView()方法。

9.呼叫WindowManagerImpl的addView()方法,流程如下:

  • 檢查新增的視窗是否已經新增過,不能重複新增。
  • 如果新增的視窗是子視窗型別,找到父視窗並儲存在臨時變數panelParentView中,該變數作為後面呼叫ViewRoot的setView()引數。
  • 建立一個新的ViewRoot
  • 呼叫ViewRoot的setView()。

10.完成新建一個ViewRoot物件後,需要把新建的ViewRoot物件新增到mRoots物件中。

11.呼叫ViewRoot物件的setView方法。流程如下:

  • 給ViewRoot的重要變數賦值。
  • 呼叫requestLayout(),發出介面重繪請求。
  • 呼叫sWindowSession.add(),通知Wms新增視窗。

建立子視窗或系統視窗過程和上面的類似。

如有問題請留言,轉載請註明出處。

備註:以上部分思想來自於《Android核心剖析》

相關文章