天天看點

Android應用程式視窗(Activity)實作架構簡要介紹和學習計劃

前面我們學習了SurfaceFlinger服務的實作原理。有了這個基礎之後,從本文開始,我們就可以分析Android系統在Java層的UI實作了。我們知道,在Android應用程式的四大元件中,隻有Activity元件與UI相關,它描述的是應用程式視窗,是以,我們就通過它的UI實作來分析Android系統在Java層的UI實作。本文主要是對Activity元件的UI實作作簡要介紹以及制定學習計劃。

        Activity元件的UI實作需要與WindowManagerService服務和SurfaceFlinger服務進行互動。從前面Android應用程式鍵盤(Keyboard)消息處理機制分析一文可以知道,Activity元件在啟動完成後,會通過一個類型為Session的Binder對象來請求WindowManagerService為它建立一個類型為WindowState的對象,用來描述它的視窗狀态。此外,從Android應用程式與SurfaceFlinger服務的關系概述和學習計劃這一系列的文章又可以知道,Android應用程式會通過一個類型為Client的Binder對象來請求SurfaceFlinger服務為它建立一個類型為Layer的對象,用來描述它的視窗資料。

        從Android應用程式請求SurfaceFlinger服務建立Surface的過程分析一 文又可以知道,SurfaceFlinger服務為Android應用程式建立一個類型為Layer的對象之後,會傳回一個類型為 SurfaceLayer的Binder對象給Android應用程式,這樣Android應用程式就可以通過這個Binder對象來請求 SurfaceFlinger服務來配置設定圖形緩沖區。

        綜合上述資訊,我們就可以得到Activity元件與WindowManagerService服務和SurfaceFlinger服務的互動模型,如圖1所示:

圖1 Activity元件與WindowManagerService服務和SurfaceFlinger服務的互動模型

 事實上,用來關聯Activity元件和Layer對象的SurfaceLayer對象并不是由Android應用程式請求

SurfaceFlinger服務來建立的,而是由WindowManagerService服務請求SurfaceFlinger服務來建立的。

WindowManagerService服務得到這個SurfaceLayer對象之後,再将它的一個代理對象傳回給在Android應用程式這一側的

Activity元件。這樣,Activity元件和WindowManagerService服務就可以通過同一個SurfaceLayer對象來操作

在SurfaceFlinger服務這一側的Layer對象,而操作Layer對象的目的就是為了修改Activity元件的UI。

        在前面Android應用程式與SurfaceFlinger服務的關系概述和學習計劃和Android系統Surface機制的SurfaceFlinger服務簡要介紹和學習計劃這兩個系列的文章中,我們已經分析在SurfaceFlinger服務這一側的Layer類和SurfaceLayer類的實作了。在現在的這一系列文章

中,我們主要分析在Android應用程式這一側的Activity元件與UI相關的類的實作,以及在WindowManagerService服務這一

側的WindowState類的實作。

        我們首先看Activity元件的實作,如圖2所示:

圖2 Activity元件的類關系圖

        Activity類是從ContextThemeWrapper類繼承下來的,而ContextThemeWrapper類又是從ContextWrapper類繼承下來的,最後ContextWrapper類又繼承了Context類。

        從前面Android應用程式啟動過程源代碼分析一文可以知道,Activity元件在啟動的過程中,系統會為它建立一個ContextImpl對象,用來描述它的運作上下文環境。這個

ContextImpl對象首先是通過調用Acitivity類的成員函數attach傳遞到Acticity元件内部,接着再依次通過調用父類

ContextThemeWrapper和ContextWrapper的成員函數attachBaseContext來分别儲存在它們的成員變量

mBase中。是以,ContextThemeWrapper和ContextWrapper類的成員變量mBase指向的實際上是一個

ContextImpl對象。

       從前面Android應用程式啟動過程源代碼分析一文還可以知道,系統為一個正在啟動的Activity元件建立了一個ContextImpl對象之後,還會調用這個ContextImpl對象的成員函數

setOuterContext來将正在啟動的Activity元件儲存在其成員變量mOuterContext中。這樣,一個Activity元件就可

以通過其父類ContextThemeWrapper或者ContextWrapper的成員變量mBase來通路用來描述它的運作上下文環境的一個

ContextImpl對象,同時,一個ContextImpl對象也可以通過它的成員變量mOuterContext來通路它的宿主Activity組

件。

      Activity類還有另外一個類型為WindowManager的成員變量mWindowManager,它實際上指向的一個

LocalWindowManager對象。LocalWindowManager類是用來管理應用程式視窗的,例如,用來維護應用程式視窗内部的視圖

(View)。LocalWindowManager類有一個類型為WindowManager的成員變量mWindowManager,它實際上指向的

是一個WindowManagerImpl對象。系統通過調用WindowManagerImpl類的靜态成員函數getDefault來獲得一個

WindowManagerImpl對象,然後儲存在LocalWindowManager類的成員變量mWindowManager中。這

樣,LocalWindowManager類就可以通過WindowManagerImpl類來真正實作管理應用程式視窗的功能。

      從上面的分析中,我們還看不出的一個Activity元件的視窗是如何描述的。為了弄清楚這個問題,我們繼續分析Activity類的另外一個成員變量mWindow,如圖3所示:

圖3 Window類的實作

        Activity類的成員變量mWindow的類型為Window,它用來描述一個應用程式視窗。這樣,通過這個成員變量,每一個Activity元件就都會有一個對應的Window對象,即一個對應的應用程式視窗。

 Window類有一個類型為Context的成員變量mContext。這個成員變量指向的是一個Activity對象。當系統為一個Activity

元件建立一個對應的Window對象時,就會将這個Activity元件的Context接口儲存在這個對應的Window對象的成員變量

mContext中。這樣,一個Window對象就可以通過它的成員變量mContext來通路它所描述的Activity元件的資源。

 Window類還有一個類型為Window.Callback的成員變量mCallback。這個成員變量和成員變量mContext一樣,都是指向同

一個Activity對象,因為Activity類是實作了Window.Callback接口的。當系統為一個Activity元件建立一個對應的

Window對象時,就會将這個Activity元件所實作的Window.Callback接口通過Window類的成員函數setCallback保

存在對應的Window對象的成員變量mCallback。這樣,一個Window對象就可以通過它的成員變量mCallback來将一些事件交給與它所

對應的Activity元件來處理,例如,将接收的鍵盤事件交給對應的Activity元件來處理。

 最後,Window類還有一個類型為WindowManager的成員變量mWindowManager。這個成員變量指向的是一個

LocalWindowManager對象。前面提到,Activity元件的成員變量mWindowManager指向的也是一個

LocalWindowManager對象。系統在啟動一個Activity元件的過程中,會通過Window類的成員函數

setWindowManager來将儲存在它的成員變量mWindowManager中的一個LocalWindowManager對象也儲存在對應的

Window對象的成員變量mWindowManager。這樣,一個Activity元件以及它所對應的Window對象就可以使用同一個

LocalWindowManager對象來管理它們所描述的UI了。

       事實上,Activity類的成員變量mWindow指向的并不是一個Window對象,而是一個PhoneWindow對象。也就是說,一個Activity元件的UI是使用一個PhoneWindow對象來描述的。

       Activity類的成員變量mWindow所指向的一個PhoneWindow對象是通過調用PolicyManager類的靜态成員函數makeNewWindow來建立的。PolicyManager類的實作如圖4所示:

圖4 PolicyManager類的實作

 PolicyManager類有一個類型為IPolicy的靜态成員變量sPolicy,它實際指向的是一個Policy對象。Policy類實作了

IPolicy接口的成員函數makeNewWindow,而PolicyManager類就是通過這個成員函數來為一個Activity元件建立一個

PhoneWindow對象的。

       PhoneWindow類繼承了Window類,是以,它的對象可以儲存Activity類的成員變量mWindow中。PhoneWindow類的實作如圖5所示:

圖5 PhoneWindow類的實作

 PhoneWindow類有兩個重要的成員變量mDecor和mContentParent,它們的類型分别DecorView和ViewGroup。

其中,成員變量mDecor是用描述自己的視窗視圖,而成員變量mContentParent用來描述視圖内容的父視窗。

 DecorView類繼承了FrameLayout類,而FrameLayout類又繼承了ViewGroup類,最後ViewGroup類又繼承了

View類。View類有一個成員函數draw,它是用來繪制應用程式視窗的UI的。DecorView類、FrameLayout類和

ViewGroup類都重寫了父類的成員函數draw,這樣,它們就都可以定制自己的UI。

 DecorView類所描述的應用程式視窗視圖是否需要重新繪制是由另外一個類ViewRoot來控制的。系統在啟動一個Activity元件的過程

中,會為這個Activity元件建立一個ViewRoot對象,同時還會将前面為這個Activity元件所建立的一個PhoneWindow對象的成

員變量mDecor所描述的一個視圖(DecorView)儲存在這個ViewRoot對象的成員變量mView中。這樣,這個ViewRoot對象就可

以通過調用它的成員變量mView的所描述的一個DecorView的成員函數draw來繪制一個Acitivity元件的UI了。ViewRoot類的

作用是非常大的,它除了用來控制一個Acitivity元件的UI繪制之外,還負責接收Acitivity元件的IO輸入事件,例如,鍵盤事件,這一點可

以參考前面Android應用程式鍵盤(Keyboard)消息處理機制分析一文。

        ViewRoot類的實作如圖6所示:

圖6 ViewRoot類的實作

        ViewRoot類是從Handler類繼承下來的。從前面Android應用程式消息處理機制(Looper、Handler)分析一文可以知道,從Handler類繼承下來的子類可以調用父類的成員函數sendMessage來向指定的線程的消息隊列發送消息,以及在自己重寫的成員函

數handleMessage中處理該消息。 ViewRoot類在兩種情況需要經常應用程式程序的主線程的消息隊列發送消息。

 第一種情況是當ViewRoot類從系統輸入管理器InputManager接收到鍵盤、觸摸屏等輸入事件時,它就會把這些輸入事件封裝成一個消息,并

且發送到應用程式程序的主線程的消息隊列中去進一步處理,這樣就可以保證鍵盤、觸摸屏等輸入事件可以在應用程式程序的主線程中進行處理。這一點可以參考前

面Android應用程式鍵盤(Keyboard)消息處理機制分析一文。

 第二種情況是當ViewRoot類需要重新繪制與它所關聯的一個Activity元件的UI時,它就會将這個繪制UI的操作封裝成一個消息,并且發送到

應用程式程序的主線程的消息隊列中去進一步處理,這樣同樣可以保證繪制UI的操作可以在應用程式程序的主線程中執行。

        每一個ViewRoot對象都有一個類型為View的成員變量mView,它指向了一個DecorView對象。這個DecorView對象是從哪裡來

的呢?前面提到,每一個Activity元件都有一個對應的ViewRoot對象以及一個對應的PhoneWindow對象,這個DecorView對象

就是來自于這個對應的PhoneWindow對象的成員變量mDecor。也就是說,與同一個Activity元件對應的ViewRoot對象和

PhoneWindow對象分别通過各自的成員變量mView和mDecor引用了共一個DecorView對象。

        每一個ViewRoot對象都有一個類型為WindowManager.LayoutParams的成員變量mWindowAttributes,它指

向了一個ViewGroup.LayoutParams對象,用來描述與該ViewRoot對象對應的一個Activity元件的UI布局資訊。

 從上面的描述就可以知道,每一個Activity元件都有一個對應的ViewRoot對象、View對象以及

WindowManager.LayoutParams對象。這三個對象的對應關系是由WindowManagerImpl類來維護的。具體來說,就是由

WindowManagerImpl類的成員變量mRoots、mViews和mParams所描述的三個數組來維護的。例如,假設一個應用程式程序運作

有兩個Activity元件,那麼WindowManagerImpl類的成員變量mRoots、mViews和mParams所描述的三個數組的大小就

等于2,其中,mRoots[0]、mViews[0]和mParams[0]對應于第一個啟動的Activity元件,而mRoots[1]、

mViews[1]和mParams[1]對應于第二個啟動的Activity元件。

        每一個ViewRoot對象都有一個類型為Surface的成員變量mSurface,它指向了一個Java層的Surface對象。這個Java層的

Surface對象通過它的成員變量mNativeSurface與一個C++層的Surface對象。這個C++層的Surface對象就是我們在Android應用程式與SurfaceFlinger服務的關系概述和學習計劃這一系列文章中所分析的Surface類的執行個體了。這個Surface類是用來在Android應用程式程序這一側描述應用程式視窗的。從前面Android應用程式請求SurfaceFlinger服務建立Surface的過程分析一文可以知道,在C++層中,每一個Surface對象都有一個對應的SurfaceControl對象。這個對應的SurfaceControl對象是用來設定應用程式視窗的屬性,例如,設定大小、位置等屬性。

 但是,與ViewRoot類的成員變量mSurface所對應的在C++層的Surface對象并沒有一個對應的SurfaceControl對象,這

是因為ViewRoot類并不需要設定應用程式視窗的屬性,它需要做的隻是往應用程式視窗的圖形緩沖區填充UI資料,即它需要設定的隻是應用程式視窗的紋

理。應用程式視窗的紋理儲存在Java層的Surface類的成員變量mCanvas所描述一個畫布(Canvas)中,即通過這個畫布可以通路到應用程

序視窗的圖形緩沖區。當ViewRoot類需要重新繪制與它對應的Activity元件的UI時,它就會調用它的成員函數draw來執行這個繪制的操作。

ViewRoot類的成員函數draw首先通過獲得儲存它的成員變量mSurface内部的一塊畫布,然後再将這個畫布傳遞給它的成員變量mView所描

述的一個View對象的成員函數draw。View類的成員函數draw得到了這塊畫布之後,就可以随心所欲地上面繪制應用程式視窗的紋理了。這些紋理的

繪制工作是通過Skia圖形庫API來進行的。

        那麼,應用程式視窗的屬性是由誰來管理的呢?這是由WindowManagerService服務來管理的。前面提到,在Android應用程式這一側

的Activity元件是由WindowManagerService服務來為它請求SurfaceFlinger服務建立一個Layer對象以及一個

SurfaceLayer對象的。這個SurfaceLayer對象建立完成之後,WindowManagerService服務就會将它封裝在一個

Java層的Surface對象中,以後就可以通過這個Java層的Surface對象來請求SurfaceFlinger服務設定一個對應的應用程式窗

口的屬性。

        由于Java層的Surface對象實作了Parcelable接口,是以,WindowManagerService服務在為一個Activity組

件請求SurfaceFlinger服務建立一個Layer對象以及一個SurfaceLayer對象之後,就可以将得到的Java層的Surface對

象跨程序地傳回給該Activity元件。Activity元件得到這個Surface對象之後,再使用儲存在裡面的SurfaceLayer對象來初始

化與它所對應的一個ViewRoot對象的成員變量mSurface所描述的一個Java層的Surface對象。

        那麼,WindowManagerService服務又是什麼時候會為一個Activity元件請求SurfaceFlinger服務建立一個

Layer對象以及一個SurfaceLayer對象呢?ViewRoot類有一個類型為IWindowSession的靜态成員變量

sWindowSession,它指向的實際上是一個實作了IWindowSession接口的Binder對象。這個Binder對象的類型為

Session,運作在WindowManagerService服務這一側。當一個Activity元件的UI第一次要被繪制之前,它所運作在的應用程

序程序就會通過ViewRoot類的靜态成員變量sWindowSession來向WindowManagerService服務發送一個請求。

WindowManagerService服務接收到這個請求之後,再請求SurfaceFlinger服務為這個Activity元件建立一個

Layer對象以及一個SurfaceLayer對象。這樣,這個Activity元件的UI才能真正地繪制在螢幕中。

        至此,我們就簡要分析完成了在Android應用程式這一側的Activity元件與UI相關的類的實作,接下來我們繼續分析在WindowManagerService服務這一側的WindowState類的實作。

        WindowState類的實作如圖7所示:

圖7 WindowState類的實作

 在Android應用程式這一側,每一個Activity元件在WindowManagerService服務這一側都有一個對應的

WindowState對象,用來描述Activity元件的視窗狀态。WindowState類有兩個重要的成員變量mSession和

mSurface,它們的類型分别為SurfaceSession和Surface。接下來,我們就描述這兩個成員變量的作用。

 前面提到,Activity元件是在啟動完成之後,請求WindowManagerService服務為它建立一個WindowState對象的。建立

完成這個WindowState對象之後,WindowManagerService服務再調用它的成員函數attach來為它附加一個

SurfaceSession對象。WindowState類的成員函數attach又是通過調用它的成員變量mSession所描述的一個

Session對象的成員函數windowAddedLocked來附加一個SurfaceSession對象的。

        Session類有一個類型為SurfaceSession的成員變量mSurfaceSession。當WindowState類的成員函數

attach調用Session類的成員函數windowAddedLocked來為一個WindowState對象附加一個

SurfaceSession對象的時候,後者首先會檢查它的成員變量mSurfaceSession是否已經指向了一個SurfaceSession對

象。如果如果指向了的話,那麼Session類的成員函數windowAddedLocked就什麼也不用做,否則的話,Session類的成員函數

windowAddedLocked就會建立一個SurfaceSession對象,并且儲存在它的成員變量mSurfaceSession中。

 SurfaceSession類有一個類型為int的成員變量mClient,它儲存的是一個C++層的SurfaceComposerClient對

象的位址,即每一個Java層的SurfaceSession對象在C++層都有一個對應的SurfaceComposerClient對象。當一個

SurfaceSession對象建立的時候,與它所關聯的SurfaceComposerClient對象也會同時被建立。從前面Android應用程式與SurfaceFlinger服務的連接配接過程分析一文可以知道,SurfaceComposerClient類用來描述Android應用程式程序與SurfaceFlinger服務之間的一個連接配接,即每一個與UI相關的Android應用程式程序都有一個SurfaceComposerClient對象。

 讀者可能會覺得奇怪,既然SurfaceComposerClient是用來描述Android應用程式程序與SurfaceFlinger服務的連接配接

的,那麼為什麼WindowManagerService服務會在内部建立SurfaceComposerClient對象呢?由于

WindowManagerService需要請求SurfaceFlinger服務來設定Android應用程式視窗的屬性,例如,設定應用程式視窗的

位置、大小等,是以,它就需要為每一個Android應用程式程序建立一個SurfaceComposerClient對象連接配接到

SurfaceFlinger服務中去,以便可以和SurfaceFlinger服務進行通信。

        從上面的描述我們就可以知道,在WindowManagerService服務中,每一個Android應用程式程序都對應有一個

SurfaceComposerClient對象。由于每一個SurfaceComposerClient對象都關聯有一個SurfaceSession

對象,是以,我們又可以推斷出每一個Android應用程式程序在WindowManagerService服務中都對應有一個

SurfaceSession對象。由于每一個SurfaceSession對象所屬的Session對象是一個Binder本地對象,并且它的

Binder代理對象是儲存在Android應用程式程序這一側的ViewRoot類的靜态成員變量sWindowSession中,是以,我們又可以推

斷出每一個Android應用程式程序在WindowManagerService服務都有一個對應的Session對象。綜合起來就是,每一個

Android應用程式程序在WindowManagerService服務這一側對應有一個Session對象、一個SurfaceSession對象

以及一個SurfaceComposerClient對象。由于每一個Android應用程式程序都可以運作若幹個Activity元件,是以,我們又可

以說,Activity元件與WindowServiceManager服務這一側的Session對象、SurfaceSession對象以及

SurfaceComposerClient對象是多對一的關系。

        介紹了WindowState類的成員變量mSession之後,我們接着介紹另外一個成員變量mSurface,它的類型為Surface,前面我們

已經介紹過Surface類在Android應用程式程序這一側的作用了,接下來我們就介紹它在WindowManagerService這一側的作用。

前面提到,WindowManagerService服務會在内部為每一個應用程式視窗,即每一個Activity元件,建立一個

SurfaceLayer對象,這個SurfaceLayer對象是封裝成一個Java層的Surface對象中的。在Java層的Surface類中,

有一個類型為int的成員變量mSurfaceControl,它儲存的是在C++層的一個SurfaceControl對象的位址值,即在

WindowManagerService服務這一側,每一個Java層的Surface對象在

C++層都有一個對應的SurfaceControl對象。這裡我們強調是在WindowManagerService服務這一側,是因為在前面提到,在

Android應用程式這一側,每一個Activity元件所對應的Java層的Surface對象在C++層是沒有一個對應的

SurfaceControl對象,而隻是對應有一個C++層的Surface對象。通過C++層的SurfaceControl對象可以設定應用程式窗

口的屬性,而通過C++層的Surface對象則可以設定應用程式視窗的圖形緩沖區,即設定應用程式視窗的紋理,是以,我們就可以知道應用程式視窗的屬性

是由WindowManagerService服務來設定的,而應用程式視窗的紋理是由它所在的程序負責設定的。

       至此,我們就簡要地介紹了Android應用程式視窗的實作架構了。上面所介紹的類及其互動關系可能會比較模糊,不易了解。不要緊,接下來我們會通過一系列的文章來弄清楚它們的來龍去脈:

       1. Android應用程式視窗的運作上下文的建立過程,即建立ContextImpl的建立過程;

       2. Android應用程式視窗的建立過程,即PhoneWindow的建立過程;

       3. Android應用程式視窗的視圖的建立過程,即DecorView的建立過程;

       4. Android應用程式視窗與WindowManagerService服務的連接配接過程,即WindowState的建立過程;

       5. Android應用程式視窗與SurfaceFlinger服務的連接配接過程,即Surface的建立過程;

       6. Android應用程式視窗的繪制過程,即Surface的渲染過程;

       學習了這些文章,我們就可以掌握Android應用程式視窗的實作架構了。掌握了Android應用程式視窗的實作架構之後,我們就可以再進一步去詳細地學習Android應用程式視窗的渲染過程。敬請關注!

繼續閱讀