剖析Activity、Window、ViewRootImpl和View之間的關系

Github連接
本文梳理了Activity、View、Window、ViewRoot、Surface、AMS、WMS之間的關系,由于跳轉間的流程紛繁復雜,一旦陷入代碼細節(jié)就難以自拔,下文中分析省略掉很多細節(jié),想了解的可以閱讀源碼或者閱讀相對應的書籍。

概念定義

ContextImpl:Context實現(xiàn)類。

PhoneWindow:Window唯一實現(xiàn)類。Window是一個抽象概念,是添加到WindowManager的根容器。

ViewRootImpl:ViewRootImpl是View的根,它控制了View的測量和繪制,同時持有WindowSession通過Binder與WMS通信,同時持有IWindow作為WSM的回調(diào)接口,用于例如touch事件的回調(diào)。

ViewRootImpl與WMS.png

WindowManagerImpl:WindowManager和ViewManager的實現(xiàn)類,通過WindowManagerGlobal與WMS通信。

DecorView:繼承FrameLayout,是視圖樹的根布局。

ViewTree.png

使用AS自帶的tools/layout inspector可以看出,整個DecorView包含了三部分:navigationBarBackground為導航欄,statusBarBackground為狀態(tài)欄,LinearLayout為當中內(nèi)容部分,展開LinearLayout.FrameLayout,可以得到action_bar_container即actionbar或toolbar和content(R.id.content)即真正setContentView的目標。

下文中但凡遇到抽象類/接口,都用實現(xiàn)類替代,而 -> 符號代表由函數(shù)跳轉到另一函數(shù)。

從啟動Activity說起

第一個部分是啟動Activity到創(chuàng)建出ViewRootImpl。

startActivity.png

從ContextImpl開始,省略掉AMS里相關跳轉到最后ActivityThread.performLaunchActivity -> Activity.attach中創(chuàng)建出PhoneWindow。

繼續(xù)下一步調(diào)用方法 ActivityThread.handleResumeActivity -> WindowManagerImpl.addView創(chuàng)建出ViewRootImpl。

WindowManagerGlobal.addView.png

ViewRootImpl的構造方法內(nèi)創(chuàng)建了WindowSession(Binder),通過它與WindowManagerService進行通信。

小結:啟動Activity會創(chuàng)建ViewRootImpl和PhoneWindow,建立起與WMS的連接。

與WMS通信

第二步是ViewRootImpl與WMS通信。

addwindow.png

接上第一步中在ViewRootImpl構造方法中通過WindowSession -> Binder.openSession構造出WindowSession。

由第一步7中WindowManagerImpl.addView -> … ->WMS.relayoutWindow根據(jù)Window測量的大小相對應創(chuàng)建出SurfaceControl,通過SurfaceControl.getSurface將測量結果寫入outSurface內(nèi),此處的outSurface就是ViewRootImpl.mSurface,注意此處只有大小,還未有指向native surface的指針mNativeObject。

WMS.createSurfaceControl.png

由第一步7中WindowManagerImpl.addView -> … ->WindowState.attch,創(chuàng)建出WindowToken用來標識Window類型,如子窗體(1000-1999),應用窗體(1-99)和系統(tǒng)窗體(2000-2999)。再創(chuàng)建WindowState——WMS端的Window對象,它持有Session與WindowManager通信,更重要的是調(diào)用Session.windowAddedLocked創(chuàng)建出SurfaceSession。

Session.windowAddedLocked.png

SurfaceSession構造方法里調(diào)用了nativeCreate,從這里開始就是native的世界,不是本文重點,但簡單概括一下流程是通過創(chuàng)建SurfaceComposerClient與SurfaceFlinger進行交互,鎖定一塊共享內(nèi)存,通過writeParcel返回給ViewRootImpl.mSurface,同時擁有了native surface的地址。

小結:當Activity準備顯示時,會測量Window和添加Window,創(chuàng)建出WMS服務對應的WindowState,Surface和native Surface。

繪制

繪制四要素:bitmap(一塊內(nèi)存保存像素),canvas(畫布用于畫像素),paint(畫筆),path(畫的對象)。

應用無論是使用View/Canvas繪制(軟件繪制,Skia),或者使用硬件加速繪制,最底層都是與Surface(OpenGL)進行交互。

再回到Activity的生命周期onCreate,調(diào)用setContentView創(chuàng)建一個不可見的DecorView,當ActivityThread.handleResumeActivity -> Activity.makeVisible設置DecorView為可見。

其中繪制的起點是ViewRootImpl.performTraversals -> ViewRootImpl.performMeasure -> ViewRootImpl.performLayout - > ViewRootImpl.performDraw調(diào)用作為根視圖DecorView的measure,layout,draw方法來遍歷視圖樹。

值得一提的是FrameBuffer的知識點,開始繪制時,會調(diào)用Surface.lockCanvas,由SurfaceFlinger鎖定一塊共享內(nèi)存?zhèn)鬟f給Canvas,內(nèi)存共享的是設備顯存,在上面繪制相當于在屏幕上繪畫。繪制結束調(diào)用Surface.unlockCanvasAndPost,從Suface上detach掉canvas,釋放Surface。

觸類旁通之SurfaceView

SurfaceView會創(chuàng)建一個Z軸靠下的新Window,通過挖洞(重疊區(qū)域變透明)使自己可見。

觀察一下SurfaceView的內(nèi)部結構,似乎和ViewRootImpl差不多,同時持有IWindowSession,Surface和MyWindow(同ViewRootImple.WindowSession)

SurfaceView.png

relayoutWindow,addWindow,Surface一氣呵成,流程比較簡單,注意一下SurfaceHolder,一般使用SurfaceView時候都是操作SurfaceHolder.Callback,它作為內(nèi)部類一開始就創(chuàng)建出來了,而在native surface創(chuàng)建完畢之后調(diào)用SurfaceHolder.Callback.surfaceCreated。

SurfaceView.updateWindow.png

總結

Activity啟動時除了通過ViewRootImpl讀取各個參數(shù)確定Window的大小,位置等等,通過WMS創(chuàng)建出相應大小的Surface和一塊共享內(nèi)存,等待DecorView通過Canvas繪制畫面。

參考資料

Android 7.1.1 源碼

Android官方文檔

《Android開發(fā)藝術探索》

《深入理解Android 卷1》

其他優(yōu)秀的中英文文章

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容