Android寶典|View必考知識(shí)點(diǎn)總結(jié)

目錄

  1. 思維導(dǎo)圖
  2. 概述
  3. 參考

思維導(dǎo)圖

概述

  1. 初始化 PhoneWindow 和 WindowManager
  2. 初始化 DecorView
  3. ViewRootImpl 的創(chuàng)建和關(guān)聯(lián) DecorView
  4. 建立 PhoneWindow 和 WMS 之間的連接
  5. 建立與 SurfaceFlinger 之間的連接
  6. 申請(qǐng) Surface
  7. 正式繪制 View 并顯示

步驟一:初始化 PhoneWindow 和 WindowManager

我們知道,Activity 是在 ActivityThread 的 performLaunchActivity 中進(jìn)行創(chuàng)建的眯停,在創(chuàng)建完成之后就會(huì)調(diào)用其 attach 方法毛肋,它是先于 onCreate、onStart、onResume 等生命周期函數(shù)的,因此將 attach 方法作為這篇文章主線的開(kāi)頭:

   // Activity#attach():
   
    final void attach(...) {
        attachBaseContext(context);
        //初始化 PhoneWindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        
        //初始化 WindowManager
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        mWindowManager = mWindow.getWindowManager();
    }

    // Window#setWindowManager():

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        //...
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

attach() 方法就是 new 一個(gè) PhoneWindow 并且關(guān)聯(lián) WindowManager。

步驟二:初始化 DecorView

接下來(lái)就到了 onCreate 方法:

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}
public void setContentView(int layoutResID) {
    installDecor();
    mLayoutInflater.inflate(layoutResID, mContentParent)
}

這一步就是把我們的布局文件解析成 View 塞到 DecorView 的一個(gè) id 為 R.id.content 的 ContentView 中肴楷,DecorView 本身是一個(gè) FrameLayout,它還承載了 StatusBar敢课、NavigationBar 。

步驟三:ViewRootImpl 的創(chuàng)建和關(guān)聯(lián) DecorView

然后在 handleResumeActivity 中绷杜,通過(guò) WindowManager 的 addView 方法把 DecorView 添加進(jìn)去直秆,實(shí)際實(shí)現(xiàn)是 WindowManagerImpl 的 addView 方法,它里面再通過(guò) WindowManagerGlobal 的實(shí)例去 addView 的鞭盟,在它里面就會(huì) new 一個(gè) ViewRootImpl圾结,也就是說(shuō)最后是把 DecorView 傳給了 ViewRootImpl 的 setView 方法。ViewRootImpl 是 DecorView 的管理者齿诉,它負(fù)責(zé) View 樹(shù)的測(cè)量筝野、布局、繪制粤剧,以及通過(guò) Choreographer 來(lái)控制 View 的刷新歇竟。

步驟四:建立 PhoneWindow 和 WindowManagerService 之間的連接

WMS 是所有 Window 窗口的管理員,負(fù)責(zé) Window 的添加和刪除抵恋、Surface 的管理和事件派發(fā)等等焕议,因此每一個(gè) Activity 中的 PhoneWindow 對(duì)象如果需要顯示等操作,就必須要與 WMS 交互才能進(jìn)行弧关。

在 ViewRootImpl 的 setView 方法中盅安,會(huì)調(diào)用 requestLayout唤锉,并且通過(guò) WindowSession 的 addToDisplay 與 WMS 進(jìn)行交互。WMS 會(huì)為每一個(gè) Window 關(guān)聯(lián)一個(gè) WindowStatus别瞭。

步驟五:建立與 SurfaceFlinger 的連接

SurfaceFlinger 主要是進(jìn)行 Layer 的合成和渲染窿祥。

在 WindowStatus 中,會(huì)創(chuàng)建 SurfaceSession蝙寨,SurfaceSession 會(huì)在 Native 層構(gòu)造一個(gè) SurfaceComposerClient 對(duì)象晒衩,它是應(yīng)用程序與 SurfaceFlinger 溝通的橋梁。

步驟六:申請(qǐng) Surface

經(jīng)過(guò)步驟四和步驟五之后籽慢,ViewRootImpl 與 WMS浸遗、SurfaceFlinger 都已經(jīng)建立起連接,但此時(shí) View 還沒(méi)顯示出來(lái)箱亿,我們知道跛锌,所有的 UI 最終都要通過(guò) Surface 來(lái)顯示,那么 Surface 是什么時(shí)候創(chuàng)建的呢届惋?

這就要回到前面所說(shuō)的 ViewRootImpl 的 requestLayout 方法了髓帽,首先會(huì) checkThread 檢查是否是主線程,然后調(diào)用 scheduleTraversals 方法脑豹,scheduleTraversals 方法會(huì)先設(shè)置同步屏障郑藏,然后通過(guò) Choreographer 類(lèi)在下一幀到來(lái)時(shí)去執(zhí)行 doTraversal 方法。簡(jiǎn)單來(lái)說(shuō)瘩欺,Choreographer 內(nèi)部會(huì)接受來(lái)自 SurfaceFlinger 發(fā)出的 Vsync 垂直同步信號(hào)必盖,這個(gè)信號(hào)周期一般是 16ms 左右。doTraversal 方法首先會(huì)先移除同步屏障俱饿,然后 performTraversals 真正進(jìn)行 View 的繪制流程歌粥,即調(diào)用 performMeasure、performLayout拍埠、performDraw失驶。不過(guò)在它們之前,會(huì)先調(diào)用 relayoutWindow 通過(guò) WindowSession 與 WMS 進(jìn)行交互枣购,即把 Java 層創(chuàng)建的 Surface 與 Native 層的 Surface 關(guān)聯(lián)起來(lái)嬉探。

步驟七:正式繪制 View 并顯示

接下來(lái)就是正式繪制 View 了,從 performTraversals 開(kāi)始棉圈,Measure涩堤、Layout、Draw 三步走分瘾。

第一步是獲取 DecorView 的寬高的 MeasureSpec 然后執(zhí)行 performMeasure 流程定躏。MeasureSpec 簡(jiǎn)單來(lái)說(shuō)就是一個(gè) int 值,高 2 位表示測(cè)量模式,低 30 位用來(lái)表示大小痊远。策略模式有三種垮抗,EXACTLY、AT_MOST碧聪、UNSPECIFIED冒版。EXACTLY 對(duì)應(yīng)為 match_parent 和具體數(shù)值的情況,表示父容器已經(jīng)確定 View 的大谐炎恕辞嗡;AT_MOST 對(duì)應(yīng) wrap_content,表示父容器規(guī)定 View 最大只能是 SpecSize滞造;UNSPECIFIED 表示不限定測(cè)量模式续室,父容器不對(duì) View 做任何限制,這種適用于系統(tǒng)內(nèi)部谒养。接著說(shuō)挺狰,performMeasure 中會(huì)去調(diào)用 DecorView 的 measure 方法,這個(gè)是 View 里面的方法并且是 final 的买窟,它里面會(huì)把參數(shù)透?jìng)鹘o onMeasure 方法丰泊,這個(gè)方法是可以重寫(xiě)的,也就是我們可以干預(yù) View 的測(cè)量過(guò)程始绍。在 onMeasure 中也物,會(huì)通過(guò) getDefaultSize 獲取到寬高的默認(rèn)值科平,然后調(diào)用 setMeasureDimension 將獲取的值進(jìn)行設(shè)置。在 getDefaultSize 中终蒂,無(wú)論是 EXACTLY 還是 AT_MOST缰猴,都會(huì)返回 MeasureSpec 中的大小丹墨,這個(gè) SpecSize 就是測(cè)量后的最終結(jié)果龟虎。至于 UNSPECIFIED 的情況俘种,則會(huì)返回一個(gè)建議的最小值,這個(gè)值和子元素設(shè)置的最小值以及它的背景大小有關(guān)篇亭。從這個(gè)默認(rèn)實(shí)現(xiàn)來(lái)看缠捌,如果我們自定義一個(gè) View 不重寫(xiě)它的 onMeasure 方法锄贷,那么 warp_content 和 match_parent 一樣译蒂。所以 DecorView 重寫(xiě)了 onMeasure 函數(shù),它本身是一個(gè) FrameLayout谊却,所以最后也會(huì)調(diào)用到 FrameLayout 的 onMeasure 函數(shù)柔昼,作為一個(gè) ViewGroup,都會(huì)遍歷子 View 并調(diào)用子 View 的 measure 方法炎辨。這樣便實(shí)現(xiàn)了層層遞歸調(diào)用到了每個(gè)子 View 的 onMeasure 方法進(jìn)行測(cè)量捕透。

第二步是執(zhí)行 performLayout 的流程,也就是調(diào)用到 DecorView 的 layout 方法,也就是 View 里面的方法乙嘀,如果 View 大小發(fā)生變化末购,則會(huì)回調(diào) onSizeChanged 方法,如果 View 狀態(tài)發(fā)生變化虎谢,則會(huì)回調(diào) onLayout 方法盟榴,這個(gè)方法在 View 中是空實(shí)現(xiàn),因此需要看 DecorView 的父容器 FrameLayout 的 onLayout 方法婴噩,這個(gè)方法就是遍歷子 View 調(diào)用其 layout 方法進(jìn)行布局擎场,子 View 的 layout 方法被調(diào)用的時(shí)候,它的 onLayout 方法又會(huì)被調(diào)用几莽,這樣就布局完了所有的 View迅办。

第三步就是 performDraw 方法了,里面會(huì)調(diào)用 drawSoftware 方法章蚣,這個(gè)方法需要先通過(guò) mSurface lockCanvas 獲取一個(gè) Canvas 對(duì)象站欺,作為參數(shù)傳給 DecorView 的 draw 方法。這個(gè)方法調(diào)用的是 View 的 draw 方法究驴,先繪制 View 背景镊绪,然后繪制 View 的內(nèi)容,如果有子 View 則會(huì)調(diào)用子 View 的 draw 方法洒忧,層層遞歸調(diào)用蝴韭,最終完成繪制。

完成這三步之后熙侍,會(huì)在 ActivityThread 的 handleResumeActivity 最后調(diào)用 Activity 的 makeVisible榄鉴,這個(gè)方法就是將 DecorView 設(shè)置為可見(jiàn)狀態(tài)。

參考

https://juejin.im/post/5c67c1e16fb9a04a05403549

https://juejin.im/post/5bf16ff5f265da6141712acc

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蛉抓,一起剝皮案震驚了整個(gè)濱河市庆尘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌巷送,老刑警劉巖驶忌,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異笑跛,居然都是意外死亡付魔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)飞蹂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)几苍,“玉大人,你說(shuō)我怎么就攤上這事陈哑∑薨樱” “怎么了伸眶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)刽宪。 經(jīng)常有香客問(wèn)我厘贼,道長(zhǎng),這世上最難降的妖魔是什么圣拄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任涂臣,我火速辦了婚禮,結(jié)果婚禮上售担,老公的妹妹穿的比我還像新娘赁遗。我一直安慰自己,他們只是感情好族铆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布岩四。 她就那樣靜靜地躺著,像睡著了一般哥攘。 火紅的嫁衣襯著肌膚如雪剖煌。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天逝淹,我揣著相機(jī)與錄音耕姊,去河邊找鬼。 笑死栅葡,一個(gè)胖子當(dāng)著我的面吹牛茉兰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欣簇,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼规脸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了熊咽?” 一聲冷哼從身側(cè)響起莫鸭,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎横殴,沒(méi)想到半個(gè)月后被因,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衫仑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年梨与,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惑畴。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛋欣,死狀恐怖航徙,靈堂內(nèi)的尸體忽然破棺而出如贷,到底是詐尸還是另有隱情陷虎,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布杠袱,位于F島的核電站尚猿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏楣富。R本人自食惡果不足惜凿掂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望纹蝴。 院中可真熱鬧庄萎,春花似錦、人聲如沸塘安。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)兼犯。三九已至忍捡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間切黔,已是汗流浹背砸脊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纬霞,地道東北人凌埂。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像诗芜,于是被迫代替她去往敵國(guó)和親侨舆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

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