剖析Activity瓮钥、Window筋量、ViewRootImpl和View之間的關(guān)系

Github連接
本文梳理了Activity、View碉熄、Window桨武、ViewRoot、Surface锈津、AMS呀酸、WMS之間的關(guān)系,由于跳轉(zhuǎn)間的流程紛繁復(fù)雜琼梆,一旦陷入代碼細(xì)節(jié)就難以自拔性誉,下文中分析省略掉很多細(xì)節(jié),想了解的可以閱讀源碼或者閱讀相對(duì)應(yīng)的書籍茎杂。

概念定義

ContextImpl:Context實(shí)現(xiàn)類错览。

PhoneWindow:Window唯一實(shí)現(xiàn)類。Window是一個(gè)抽象概念煌往,是添加到WindowManager的根容器倾哺。

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

ViewRootImpl與WMS.png

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

DecorView:繼承FrameLayout翘地,是視圖樹的根布局申尤。

ViewTree.png

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

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

從啟動(dòng)Activity說(shuō)起

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

startActivity.png

從ContextImpl開始和簸,省略掉AMS里相關(guān)跳轉(zhuǎn)到最后ActivityThread.performLaunchActivity -> Activity.attach中創(chuàng)建出PhoneWindow彭雾。

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

WindowManagerGlobal.addView.png

ViewRootImpl的構(gòu)造方法內(nèi)創(chuàng)建了WindowSession(Binder)锁保,通過它與WindowManagerService進(jìn)行通信薯酝。

小結(jié):?jiǎn)?dòng)Activity會(huì)創(chuàng)建ViewRootImpl和PhoneWindow,建立起與WMS的連接爽柒。

與WMS通信

第二步是ViewRootImpl與WMS通信吴菠。

addwindow.png

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

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

WMS.createSurfaceControl.png

由第一步7中WindowManagerImpl.addView -> … ->WindowState.attch,創(chuàng)建出WindowToken用來(lái)標(biāo)識(shí)Window類型嗓化,如子窗體(1000-1999)棠涮,應(yīng)用窗體(1-99)和系統(tǒng)窗體(2000-2999)。再創(chuàng)建WindowState——WMS端的Window對(duì)象刺覆,它持有Session與WindowManager通信严肪,更重要的是調(diào)用Session.windowAddedLocked創(chuàng)建出SurfaceSession。

Session.windowAddedLocked.png

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

小結(jié):當(dāng)Activity準(zhǔn)備顯示時(shí)帘睦,會(huì)測(cè)量Window和添加Window袍患,創(chuàng)建出WMS服務(wù)對(duì)應(yīng)的WindowState,Surface和native Surface竣付。

繪制

繪制四要素:bitmap(一塊內(nèi)存保存像素)诡延,canvas(畫布用于畫像素),paint(畫筆)古胆,path(畫的對(duì)象)肆良。

應(yīng)用無(wú)論是使用View/Canvas繪制(軟件繪制,Skia)逸绎,或者使用硬件加速繪制惹恃,最底層都是與Surface(OpenGL)進(jìn)行交互。

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

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

值得一提的是FrameBuffer的知識(shí)點(diǎn)疲牵,開始繪制時(shí)承二,會(huì)調(diào)用Surface.lockCanvas,由SurfaceFlinger鎖定一塊共享內(nèi)存?zhèn)鬟f給Canvas纲爸,內(nèi)存共享的是設(shè)備顯存亥鸠,在上面繪制相當(dāng)于在屏幕上繪畫。繪制結(jié)束調(diào)用Surface.unlockCanvasAndPost识啦,從Suface上detach掉canvas负蚊,釋放Surface。

觸類旁通之SurfaceView

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

觀察一下SurfaceView的內(nèi)部結(jié)構(gòu),似乎和ViewRootImpl差不多冕茅,同時(shí)持有IWindowSession伤极,Surface和MyWindow(同ViewRootImple.WindowSession)

SurfaceView.png

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

SurfaceView.updateWindow.png

總結(jié)

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

參考資料

Android 7.1.1 源碼

Android官方文檔

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

《深入理解Android 卷1》

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缺虐,隨后出現(xiàn)的幾起案子芜壁,更是在濱河造成了極大的恐慌,老刑警劉巖高氮,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慧妄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡剪芍,警方通過查閱死者的電腦和手機(jī)塞淹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)罪裹,“玉大人饱普,你說(shuō)我怎么就攤上這事∽垂玻” “怎么了套耕?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)峡继。 經(jīng)常有香客問我冯袍,道長(zhǎng),這世上最難降的妖魔是什么碾牌? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任康愤,我火速辦了婚禮,結(jié)果婚禮上舶吗,老公的妹妹穿的比我還像新娘征冷。我一直安慰自己,他們只是感情好誓琼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布资盅。 她就那樣靜靜地躺著调榄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呵扛。 梳的紋絲不亂的頭發(fā)上每庆,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音今穿,去河邊找鬼缤灵。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蓝晒,可吹牛的內(nèi)容都是我干的腮出。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芝薇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胚嘲!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起洛二,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤馋劈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后晾嘶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妓雾,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年垒迂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了械姻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡机断,死狀恐怖楷拳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吏奸,我是刑警寧澤唯竹,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站苦丁,受9級(jí)特大地震影響浸颓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旺拉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一产上、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛾狗,春花似錦晋涣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)算吩。三九已至,卻和暖如春佃扼,著一層夾襖步出監(jiān)牢的瞬間偎巢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工兼耀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留压昼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓瘤运,卻偏偏與公主長(zhǎng)得像窍霞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拯坟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容