Android 檢視架構詳解

remcarpediem發表於2016-08-29

最近一直在研究View的繪製相關的機制,發現需要補充一下Android View Architecture的相關知識,所以就特地研究了一下這方面的程式碼,寫成本篇文章
為了節約你的時間,本篇文章內容大致如下:

  • ActivityDecorViewPhoneWindowViewRoot的作用和相關關係

Android View Architecture

先來幾張圖,大致展現一下Android 檢視架構的大概。

感謝網友提醒,泛化和實現這兩種關係的箭頭畫反啦。以後要仔細學一遍UML了,平時經常畫,如果有錯誤可真是鬧笑話啊。

20160417151132961

20160417151156211

20160417151223484

Activity和Window

總所周知,Activity並不負責檢視控制,它只是控制生命週期和處理事件,真正控制檢視的是Window。一個Activity包含了一個Window,Window才是真正代表一個視窗,也就是說Activity可以沒有Window,那就相當於是Service了。在ActivityThread中也有控制Service的相關函式或許正好印證了這一點。
ActivityWindow的第一次邂逅是在ActivityThread呼叫Activityattach()函式時。

attach()中,新建一個Window例項作為自己的成員變數,它的型別為PhoneWindow,這是抽象類Window的一個子類。然後設定mWindowWindowManager

Window,Activity和DecorView

DecorViewFrameLayout的子類,它可以被認為是Android檢視樹的根節點檢視。DecorView作為頂級View,一般情況下它內部包含一個豎直方向的LinearLayout,在這個LinearLayout裡面有上下兩個部分(具體情況和Android版本及主體有關),上面的是標題欄,下面的是內容欄。在Activity中通過setContentView所設定的佈局檔案其實就是被加到內容欄之中的,而內容欄的id是content,在程式碼中可以通過ViewGroup content = (ViewGroup)findViewById(R.android.id.content)來得到content對應的layout。
Window中有幾個檢視相關的比較重要的成員變數如下所示:

  • mDecor:DecorView的例項,標示Window內部的頂級檢視
  • mContentParent:setContetView所設定的佈局檔案就加到這個檢視中
  • mContentRoot:是DecorView的唯一子檢視,內部包含mContentParent,標題欄和狀態列。

Activity中不僅持有一個Window例項,還有一個型別為ViewmDecor例項。這個例項和Window中的mDecor例項有什麼關係呢?它又是什麼時候被建立的呢?
二者其實指向同一個物件,這個物件是在Activity呼叫setContentView時建立的。我們都知道ActivitysetContentView實際上是呼叫了WindowsetContentView方法。

程式碼很清楚的顯示了佈局檔案的檢視是新增到mContentParent中,而且Window通過installDecor來新建DecorView

從上述的程式碼中,我們可以清楚的看到mDecormContentParentmContentRoot的關係。
那麼,Activity中的mDecor是何時被賦值的?我們如何確定它和Widnow中的mDecor指向同一個物件呢?我們可以檢視ActivityThreadhandleResumeActivity函式,它負責處理Activityresume階段。在這個函式中,Android直接將Window中的DecorView例項賦值給Activity

Window,DecorView 和 ViewRoot

ViewRoot對應ViewRootImpl類,它是連線WindowManagerServiceDecorView的紐帶,View的三大流程(測量(measure),佈局(layout),繪製(draw))均通過ViewRoot來完成。ViewRoot並不屬於View樹的一份子。從原始碼實現上來看,它既非View的子類,也非View的父類,但是,它實現了ViewParent介面,這讓它可以作為View的名義上的父檢視。RootView繼承了Handler類,可以接收事件並分發,Android的所有觸屏事件、按鍵事件、介面重新整理等事件都是通過ViewRoot進行分發的。ViewRoot可以被理解為“View樹的管理者”——它有一個mView成員變數,它指向的物件和上文中WindowActivitymDecor指向的物件是同一個物件

我們來先看一下ViewRoot的建立過程。由於ViewRoot作為WindowMangerServiceDecorView的紐帶,只有在WindowManager將持有DecorViewWindow新增進視窗管理器才建立。我們可以檢視WindowMangerGlobal中的addView函式。對WindowManager不太熟悉的同學可以參考《Window和WindowManager解析》

那麼,Window是什麼時候被新增到WindowManager中的呢?我們回到ActivityThreadhandleResumeActivity函式。我們都知道Activity的resume階段就是要顯示到螢幕上的階段,在Activity也就是DecorView將要顯示到螢幕時,系統才會呼叫addView方法。
我們在handleResumeActivity函式中找到了下面一段程式碼,它呼叫了ActivitymakeVisible()函式。

我們通過原始碼發現,正式在makeVisible函式中,系統進行了Window的新增。

引用

http://wiki.jikexueyuan.com/project/deep-android-v1/surface.html
http://blog.csdn.net/guxiao1201/article/details/41744107
http://forlan.iteye.com/blog/2269381

相關文章