日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

圖解Android

 老匹夫 2014-03-29

 

Android 的窗口管理系統(tǒng) (View, Canvas, WindowManager)

圖解Android - Zygote 和 System Server 啟動(dòng)分析一 文里,我們已經(jīng)知道Android 應(yīng)用程序是怎么創(chuàng)建出來(lái)的,大概的流程是 ActivityManagerService -> Zygote -> Fork App, 然后應(yīng)用程序在ActivityThread 中的進(jìn)入loop循環(huán)等待處理來(lái)自AcitivyManagerService的消息。如果一個(gè)Android的應(yīng)用有Acitivity, 那它起來(lái)后的第一件事情就是將自己顯示出來(lái),這個(gè)過(guò)程是怎樣的? 這就是本章節(jié)要討論的話(huà)題。

 

Android 中跟窗口管理相關(guān)(不包括顯示和按鍵處理)主要有兩個(gè)進(jìn)程,Acitivty所在進(jìn)程 和 WndowManagerService 所在進(jìn)程(SystemServer).  上圖中用不同顏色區(qū)分這兩個(gè)進(jìn)程,黃色的模塊運(yùn)行在Activity的進(jìn)程里,綠色的模塊則在System Server內(nèi)部,本文主要討論的是WindowManager Service。它們的分工是,Activity進(jìn)程負(fù)責(zé)窗口內(nèi)View的管理,而WindowManager Service 管理來(lái)自與不同Acitivity以及系統(tǒng)的的窗口。

1. Acitivty顯示前的準(zhǔn)備工作

圖解Android - Zygote, System Server 啟動(dòng)分析中我們已經(jīng)知道,一個(gè)新的應(yīng)用被fork完后,第一個(gè)調(diào)用的方法就是 ActivityThread的main(),這個(gè)函數(shù)主要做的事情就是創(chuàng)建一個(gè)ActivityThread線(xiàn)程,然后調(diào)用loop()開(kāi)始等待。當(dāng)收到來(lái)自 ActivityManager 的 LAUNCH_ACTIVITY 消息后,Activity開(kāi)始了他的顯示之旅。下圖描繪的是Activity在顯示前的準(zhǔn)備流程。


 

圖分為三部分, 右上角是Acitivity應(yīng)用的初始化。中間部分是Acitivity 與WindowManager Service的交互準(zhǔn)備工作,左下角是window顯示的開(kāi)始。本文主要描述后兩部分,而Activity的啟動(dòng)會(huì)放在圖解Android - Android GUI 系統(tǒng) (4) - Activity的生命周期里講解。

  1. Activity內(nèi)部的準(zhǔn)備過(guò)程,這里面有一個(gè)重要對(duì)象,ContextImpl 生成,它是Context類(lèi)的具體實(shí)現(xiàn),它里面封裝了應(yīng)用程序訪(fǎng)問(wèn)系統(tǒng)資源的一些基本API, 比如說(shuō),連接某一個(gè)服務(wù)并獲取其IBinder,發(fā)送Intent, 獲取應(yīng)用程序的信息,訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)等等,在應(yīng)用看來(lái),它就是整個(gè)AndroidSDK的入口。ContextImpl 除了實(shí)現(xiàn)函數(shù),里面還維護(hù)成員變量,其中有一個(gè)mDisplay,代表當(dāng)前應(yīng)用輸出的顯示設(shè)備,如果應(yīng)用沒(méi)有特別指定,一般指向系統(tǒng)的默認(rèn)顯示輸出,比如手機(jī)的液晶屏。
  2. 圖解Android - Android GUI 系統(tǒng) (1) - 概論中我們已經(jīng)介紹過(guò)ViewRootImpl 的地位相當(dāng)與MVC架構(gòu)中的C,Controller是連接View和Modal的關(guān)鍵,所以需要首先創(chuàng)建它。當(dāng)addView(view, param)被調(diào)用的時(shí)候,一個(gè)ViewRoot就被創(chuàng)建出來(lái),addView()的實(shí)現(xiàn)如下:
    public void addView(View view, ViewGroup.LayoutParams params) {
            mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
    public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow){
           ...
           root = new ViewRootImpl(view.getContext(), display);
           ...
    }

    這里的參數(shù)View是想要添加到WindowManagerService 的“window", 一般一個(gè)Activity只需要一個(gè)’Window', 所以,Acitivy的默認(rèn)實(shí)現(xiàn)是將DecorView作為”Window" 交給Window Manager Service 進(jìn)行管理。Params是Layout相關(guān)的參數(shù),里面包含有長(zhǎng),寬,邊緣尺寸(Margin)等信息,mDisplay就是這個(gè)窗口想要輸出的Display設(shè)備編號(hào),由ContextImpl傳遞過(guò)來(lái)。mParentWindow 就是Activity的成員變量mWindow,從最上面的類(lèi)圖可以很容易看出來(lái),對(duì)于手機(jī)而言,就是一個(gè)PhoneWindow對(duì)象,對(duì)于GoogleTV,就是TVWindow對(duì)象。

  3. ViewRootImpl 在構(gòu)造過(guò)程成初始化一些重要的成員變量,包括一個(gè)Surface對(duì)象(注意這是一個(gè)空的Surface對(duì)象,沒(méi)有賦給任何有效的值,后面會(huì)通過(guò)CopyFromParcel來(lái)填充),還有mChoreophaer定時(shí)器(Singleton對(duì)象,每個(gè)進(jìn)程只有一個(gè)),與此同時(shí),ViewRootImp通過(guò)WindowManagerGlobal創(chuàng)建了一個(gè)和WindowManagerService 的通話(huà)通道,接下來(lái)會(huì)利用這條通道做進(jìn)一步的初始化工作。
  4. 還是在addView()里,WindowManagerImpl拿到ViewRoot對(duì)象后調(diào)用它的setView方法,將view, layout參數(shù)交給ViewRootImpl開(kāi)始接管。在setView()里ViewRootImpl做進(jìn)一步的初始化工作,包括創(chuàng)建一個(gè)InputChannel接收用戶(hù)按鍵輸入,enable圖形硬件加速,請(qǐng)求第一次的Layout等等,這里只介紹跟WindowManagerService 有關(guān)系的一件事,就是向WindowManager service 報(bào)道,加入到WindowManager的窗口管理隊(duì)列中。這個(gè)函數(shù)是 addToDisplay(),
    int addToDisplay(in IWindow window,  //提供給WMS的回調(diào)接口
         in int seq, 
         in windowManager.LayoutParams attrs,  // layout參數(shù)
         in int viewVisibility, in int layerStackId,     // display ID
         out Rect outContentInsets,                      // WMS計(jì)算后返回這個(gè)View在顯示屏上的位置
         out InputChannel outInputChannel);       // 用戶(hù)輸入通道Handle

    addToDisplay() 最終會(huì)調(diào)到WindowManager Service的addWindow() 接口。

  5. addWindow() 里首先生成了一個(gè)WindowState對(duì)象,它是ViewRootImpl 在WindowManager Service端的代表。在它的構(gòu)造函數(shù)里,WindowState 會(huì)生成IWindowId.Stub 對(duì)象和DeathRecipient對(duì)象來(lái)分別監(jiān)聽(tīng)Focus和窗口死亡的信息,根據(jù)用戶(hù)傳進(jìn)來(lái)的Window Type計(jì)算出窗口的mBaseLayer,mSubLayer和mLastLayer值,分別對(duì)應(yīng)于主窗口,主窗口上彈出的子窗口(如輸入法),以及動(dòng)畫(huà)時(shí)分別對(duì)應(yīng)的ZOrder值,(在本文后面會(huì)具體介紹),生成一個(gè)WindowStateAnimation 負(fù)責(zé)整個(gè)Window的動(dòng)畫(huà),并在內(nèi)部將windowToken, appWindowToken等關(guān)聯(lián)起來(lái)。
  6. WindowManager Service 調(diào)用openInputChannelPair() and RegisterInputChannel(), 創(chuàng)建用于通信的SocketPair , 將其傳給InputManagerService, 用于接下來(lái)的用戶(hù)輸入事件對(duì)應(yīng)的響應(yīng)窗口(參考Android的用戶(hù)輸入處理),
  7. 最后,WindowManagerService 調(diào)用WindowState的attach(),創(chuàng)建了一個(gè)Surface Session 并將Surface Session,WindowSession 還有WindowState 三者關(guān)聯(lián)起來(lái).
  8. WindowManager Service 調(diào)用 assignLayersLocked()計(jì)算所有Window的Z-Order。
  9. addToDisplay() 返回,ViewRootImpl 和 WindowManager Service 內(nèi)部的準(zhǔn)備工作就緒。ActivityThread會(huì)發(fā)送ACTIVITY_RESUMED消息告訴Activity顯示開(kāi)始。可以是圖還沒(méi)有畫(huà),不是嗎?對(duì)的,此刻Surface還沒(méi)有真正初始化(我們前面說(shuō)過(guò)ViewRootImpl只是New了一個(gè)空的對(duì)象,需要有人往里面填東西)。底層存放繪制結(jié)果的Buffer也沒(méi)有創(chuàng)建,但是最多16ms以后這一切就會(huì)開(kāi)始。

2. Choreographer 和 Surface的創(chuàng)建

所有的圖像顯示輸出都是由時(shí)鐘驅(qū)動(dòng)的,這個(gè)驅(qū)動(dòng)信號(hào)稱(chēng)為VSYNC。這個(gè)名詞來(lái)源于模擬電視時(shí)代,在那個(gè)年代,因?yàn)閹挼南拗疲恳粠瑘D像都有分成兩次傳輸,先掃描偶數(shù)行(也稱(chēng)偶場(chǎng))傳輸,再回到頭部掃描奇數(shù)行(奇場(chǎng)),掃描之前,發(fā)送一個(gè)VSYNC同步信號(hào),用于標(biāo)識(shí)這個(gè)這是一場(chǎng)的開(kāi)始。場(chǎng)頻,也就是VSYNC 頻率決定了幀率(場(chǎng)頻/2). 在現(xiàn)在的數(shù)字傳輸中,已經(jīng)沒(méi)有了場(chǎng)的概念,但VSYNC這一概念得于保持下來(lái),代表了圖像的刷新頻率,意味著收到VSYNC信號(hào)后,我們必須將新的一幀進(jìn)行顯示。

VSYNC一般由硬件產(chǎn)生,也可以由軟件產(chǎn)生(如果夠準(zhǔn)確的話(huà)),Android 中VSYNC來(lái)著于HWComposer,接收者沒(méi)錯(cuò),就是Choreographer。Choreographer英文意思是編舞者,跳舞很講究節(jié)奏不是嗎,必須要踩準(zhǔn)點(diǎn)。Choreographer 就是用來(lái)幫助Android的動(dòng)畫(huà),輸入,還是顯示刷新按照固定節(jié)奏來(lái)完成工作的??纯碈hroreographer 和周邊的類(lèi)結(jié)構(gòu)。

 

 

從圖中我們可以看到, Choreographer 是ViewRootImpl 創(chuàng)建的(Choreographer是一個(gè)sigleton類(lèi),第一個(gè)訪(fǎng)問(wèn)它的ViewRootImpl創(chuàng)建它),它擁有一個(gè)Receiver, 用來(lái)接收外部傳入的Event,它還有一個(gè)Callback Queue, 里面存放著若干個(gè)CallbackRecord, 還有一個(gè)FrameHandler,用來(lái)handleMessage, 最后,它還跟Looper有引用關(guān)系。再看看下面這張時(shí)序圖,一切就清楚了,

 

 

首先Looper調(diào)用loop() 后,線(xiàn)程進(jìn)入進(jìn)入睡眠,直到收到一個(gè)消息。Looper也支持addFd()方法,這樣如果某個(gè)fd上發(fā)生了IO操作(read/write), 它也會(huì)從睡眠中醒來(lái)。Choreographer的實(shí)現(xiàn)用到了這兩種方式,首先他通過(guò)某種方式獲取到SurfaceFlinger 進(jìn)程提供的fd,然后將其交給Looper進(jìn)行監(jiān)聽(tīng),只要SurfaceFlinger往這個(gè)fd寫(xiě)入VSync事件,looper便會(huì)喚醒。Lopper喚醒后,會(huì)執(zhí)行onVsync()時(shí)間,這里面沒(méi)有做太多事情,而是調(diào)用Handler接口 sendMessageAtTime() 往消息隊(duì)列里又送了一個(gè)消息。這個(gè)消息最終調(diào)到了Handler (實(shí)際是FrameHandler)的handleCallback來(lái)完成上層安排的工作。為什么要繞這么大個(gè)圈?為什么不在onVSync里直接handleCallback()? 畢竟onVSync 和 handleCallback() 都在一個(gè)線(xiàn)程里。這是因?yàn)镸essageQueue 不光接收來(lái)自SurfaceFlinger 的VSync 事件,還有來(lái)自上層的控制消息。VSync的處理是相當(dāng)頻繁的,如果不將VSync信號(hào)送人MessageQueue進(jìn)行排隊(duì),MessageQueue里的事件就有可能得不到及時(shí)處理,嚴(yán)重的話(huà)會(huì)導(dǎo)致溢出。當(dāng)然了,如果因?yàn)閂Sync信號(hào)排隊(duì)而導(dǎo)致處理延遲,這就是設(shè)計(jì)的問(wèn)題了,這也是為什么Android文檔里反復(fù)強(qiáng)調(diào)在Activity的onXXX()里不要做太耗時(shí)的工作,因?yàn)檫@些回調(diào)函數(shù)和Choreographer運(yùn)行在同一個(gè)線(xiàn)程里,這個(gè)線(xiàn)程就是所謂的UI線(xiàn)程。

言歸正傳,繼續(xù)往前,VSync事件最終在doFrame()里調(diào)了三次doCallbacks()來(lái)完成不同的功能, 分別處理用戶(hù)輸入事件,動(dòng)畫(huà)刷新(動(dòng)畫(huà)就是定時(shí)更新的圖片), 最后執(zhí)行performTraversals(),這個(gè)函數(shù)里面主要是檢查當(dāng)前窗口當(dāng)前狀態(tài),比如說(shuō)是否依然可見(jiàn),尺寸,方向,布局是否發(fā)生改變(可能是由前面的用戶(hù)輸入觸發(fā)的),分別調(diào)用performMeasure(), performLayout, performDraw()完成測(cè)量,布局和繪制工作。我們會(huì)在后面詳細(xì)學(xué)習(xí)這三個(gè)函數(shù),這里我們主要看一下第一次進(jìn)入performTraversals的情況,因?yàn)榈谝淮螘?huì)做些初始化的工作,最重要的一件就是如本節(jié)標(biāo)題,創(chuàng)建Surface對(duì)象。

回看圖2,我們可以看到Surface的創(chuàng)建不是在Activity進(jìn)程里,而是在WindowManagerService完成的(粉顏色)。當(dāng)一個(gè)Activity第一次顯示的時(shí)候,Android顯示切換動(dòng)畫(huà),因此Surface是在動(dòng)畫(huà)的準(zhǔn)備過(guò)程中創(chuàng)建的,具體發(fā)生在類(lèi)WindowStateAnimator的createSurfaced()函數(shù)。它最終創(chuàng)建了一個(gè)SurfaceControl 對(duì)象。SurfaceControl是Android 4.3 里新引進(jìn)的類(lèi),Google從之前的Surface類(lèi)里拆出部分接口,變成SurfaceControl,為什么要這樣? 為了讓結(jié)構(gòu)更清晰,WindowManagerService 只能對(duì)Surface進(jìn)行控制,但并不更新Surface里的內(nèi)容,分拆之后,WindowManagerService 只能訪(fǎng)問(wèn)SurfaceControl,它主要控制Surface的創(chuàng)建,銷(xiāo)毀,Z-order,透明度,顯示或隱藏,等等。而真正的更新者,View會(huì)通過(guò)Canvas的接口將內(nèi)容畫(huà)到Surface上。那View怎么拿到WMService創(chuàng)建的Surface,答案是下面的代碼里,surfaceControl 被轉(zhuǎn)換成一個(gè)Surface對(duì)象,然后傳回給ViewRoot, 前面創(chuàng)建的空的Surface現(xiàn)在有了實(shí)質(zhì)內(nèi)容。Surface通過(guò)這種方式被創(chuàng)建出來(lái),Surface對(duì)應(yīng)的Buffer 也相應(yīng)的在SurfaceFlinger內(nèi)部通過(guò)HAL層模塊(GRAlloc)分配并維護(hù)在SurfaceFlinger 內(nèi)部,Canvas() 通過(guò)dequeueBuffer()接口拿到Surface的一個(gè)Buffer,繪制完成后通過(guò)queueBuffer()還給SurfaceFlinger進(jìn)行繪制。

復(fù)制代碼
                    SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
                    if (surfaceControl != null) {
                        outSurface.copyFrom(surfaceControl);
                        if (SHOW_TRANSACTIONS) Slog.i(TAG,
                                "  OUT SURFACE " + outSurface + ": copied");
                    } else {
                        outSurface.release();
                    }
復(fù)制代碼

到這里,我們知道了Activity的三大工作,用戶(hù)輸入響應(yīng),動(dòng)畫(huà),和繪制都是由一個(gè)定時(shí)器驅(qū)動(dòng)的,Surface在Activity第一次啟動(dòng)時(shí)由WindowManager Service創(chuàng)建。接下來(lái)我們具體看一下View是如何畫(huà)在Surface Buffer上的,而Surface Buffer的顯示則交由圖解Android - Android GUI 系統(tǒng) (3) - Surface Flinger 來(lái)討論。

3. View的Measure, Layout 和 Draw

直接從前面提到的performMeasure()函數(shù)開(kāi)始.

 因?yàn)檫f歸調(diào)用,實(shí)際的函數(shù)調(diào)用棧比這里顯示的深得很多,這個(gè)函數(shù)會(huì)從view的結(jié)構(gòu)樹(shù)頂(DecorView), 一直遍歷到葉節(jié)點(diǎn)。中間會(huì)經(jīng)過(guò)三個(gè)基類(lèi),DecorView, ViewGroup 和 View, 它們的類(lèi)結(jié)構(gòu)如下圖所示:

 

所有可見(jiàn)的View(不包括DecorView 和 ViewGroup)都是一個(gè)矩形,Measure的目的就是算出這個(gè)矩形的尺寸, mMeasuredWidth 和 mMeasuredHeight (注意,這不是最終在屏幕上顯示的尺寸),這兩個(gè)尺寸的計(jì)算受其父View的尺寸和類(lèi)型限制,這些信息存放在 MeasureSpec里。MeasureSpec 里定義了三種constraints,

  • 復(fù)制代碼
            /*父View對(duì)子View尺寸沒(méi)有任何要求,其可以設(shè)任意尺寸*/
            public static final int UNSPECIFIED = 0 << MODE_SHIFT;
    
            /* 父View為子View已經(jīng)指定了大小*/
            public static final int EXACTLY     = 1 << MODE_SHIFT;
    
            /*父View沒(méi)有指定子View大小,但其不能超過(guò)父View的邊界 */
            public static final int AT_MOST     = 2 << MODE_SHIFT;
    復(fù)制代碼

widthMeasureSpec 和 heightMeasureSpec 作為 onMeasure的參數(shù)出入,子View根據(jù)這兩個(gè)值計(jì)算出自己的尺寸,最終調(diào)用 setMeasuredDimension() 更新mMeasuredWidth 和 mMeasuredHeight.

performMeasure() 結(jié)束后,所有的View都更新了自己的尺寸,接下來(lái)進(jìn)入performLayout().

performLayout() 的流程和performMeasure基本上一樣,可以將上面圖中的measure() 和 onMeasure 簡(jiǎn)單的換成 layout() 和 onLayout(), 也是遍歷整課View樹(shù),根據(jù)之前算出的大小將每個(gè)View的位置信息計(jì)算出來(lái)。這里不做太多描述,我們把重心放到performDraw(), 因?yàn)檫@塊最復(fù)雜,也是最為重要的一塊。

很早就玩過(guò)Android手機(jī)的同學(xué)應(yīng)該能體會(huì)到Android2.3 到 Android 4.0 (其實(shí)Android3.0就有了,只是這個(gè)版本只在平板上有)的性能的巨大提升,UI界面的滑動(dòng)效果一下變得順滑很多,到底是framework的什么改動(dòng)帶來(lái)的?我們馬上揭曉。。。(這塊非本人工作領(lǐng)域,網(wǎng)上相關(guān)的資料也很少,所以純憑個(gè)人磚研,歡迎拍磚指正)

Android Graphics Hardware Acceleration

OK, 如標(biāo)題所述,最根本的原因就是引入了硬件加速, GPU是專(zhuān)門(mén)優(yōu)化圖形繪制的硬件單元,很多GPU(至少手機(jī)上的)都支持OpenGL,一種開(kāi)放的跨平臺(tái)的3D繪圖API。Android3.0以前,幾乎所有的圖形繪制都是由Skia完成,Skia是一個(gè)向量繪圖庫(kù),使用CPU來(lái)進(jìn)行運(yùn)算, 所以它的performance是一個(gè)問(wèn)題(當(dāng)然,Skia也可以用GPU進(jìn)行加速,有人在研究,但好像GPU對(duì)向量繪圖的提升不像對(duì)Opengl那么明顯),所以從Android3.0 開(kāi)始,Google用hwui取代了Skia,準(zhǔn)確的說(shuō),是推薦取代,因?yàn)镺pengl的支持不完全,有少量圖形api仍由Skia完成,另外還要考慮到兼容性,硬件加速的功能并不是默認(rèn)打開(kāi),需要程序在AndroidManifests.xml 或代碼里控制開(kāi)關(guān)。當(dāng)然,大部分Canvas的基本操作都通過(guò)hwui重寫(xiě)了,hwui下面就是Opengl和后面的GPU,這也是為什么Android 4.0的launcher變得異常流暢的緣故。OK,那我們接下來(lái)的重點(diǎn)就是要分析HWUI的實(shí)現(xiàn)了。

在此之前,簡(jiǎn)單的介紹一下OpenGL的一些概念,否則很難理解。要想深入理解Opengl,請(qǐng)必讀經(jīng)典的紅包書(shū):http://www./red/

Opengl說(shuō)白了,就是一組圖形繪制的API。 這些API都是一些非?;镜拿?,通過(guò)它,你可以構(gòu)造出非常復(fù)雜的圖形和動(dòng)畫(huà),同時(shí),它又是跟硬件細(xì)節(jié)無(wú)關(guān)的,所以無(wú)需改動(dòng)就可以運(yùn)行在不同的硬件平臺(tái)上(前提是硬件支持所需特性)。OpenGL的輸入是最基本幾何元素(geometric primitives), 點(diǎn)(points), 線(xiàn)(lines), 多邊形(polygons), 以及bitmap和pixle data, 他的輸出是一個(gè)或兩個(gè)Framebuffer(真3D立體). 輸入到輸出的流程(rendering pipeline)如下圖所示:

 這里有太多的概念,我們只描述跟本文相關(guān)的幾個(gè):

 vertex data
     
所有的幾何元素(點(diǎn)線(xiàn)面)都可以用點(diǎn)(vertics)來(lái)描述, 每個(gè)點(diǎn)都對(duì)應(yīng)三維空間中的一個(gè)坐標(biāo)(x,y,z), 如下圖所示,改變?nèi)舾牲c(diǎn)的位置,我們便可以構(gòu)造出一個(gè)立體的圖形。    

Triangles

     OpenGL只能畫(huà)非凹(nonconvex)的多邊形,可是現(xiàn)實(shí)世界中存在太多的凹性的物體,怎么辦呢?通過(guò)連線(xiàn)可以將凹的物體分成若干個(gè)三角形,三角形永遠(yuǎn)都是凸(convex)的。同時(shí)三角形還有一個(gè)特性,三個(gè)點(diǎn)可以唯一確定一個(gè)平面,所以用盡可能多的三角形就可以逼近現(xiàn)實(shí)世界中復(fù)雜的曲線(xiàn)表面,比如下圖的例子,三角形的數(shù)目越多,球體的表示就越逼真。這也是為什么我們經(jīng)??吹斤@卡的性能評(píng)測(cè)都以三角形的生成和處理作為一個(gè)非常重要的指標(biāo)。

 Display List

      所有的Vertex和Pixel信息均可以存在Display List 里面,用于后續(xù)處理,換句話(huà)說(shuō),Display List 就是OpenGL命令的緩存。Display List的使用對(duì)OpenGL的性能提升有很大幫助。這個(gè)很容易理解,想象一個(gè)復(fù)雜的物體,需要大量的OpenGL命令來(lái)描繪,如果畫(huà)一次都需要重新調(diào)用OpenGL API,并把它轉(zhuǎn)換成Vertex data,顯然是很低效的,如果把他們緩存在Display List里,需要重繪的時(shí)候,發(fā)一個(gè)個(gè)命令通知OpenGL直接從Display List 讀取緩存的Vertex Data,那勢(shì)必會(huì)快很多,如果考慮到Opengl是基于C/S架構(gòu),可以支持遠(yuǎn)程Client,這個(gè)提升就更大了。Display也可以緩存BitMap 或 Image, 舉個(gè)例子,假設(shè)要顯示一篇文章,里面有很多重復(fù)的字符,如果每個(gè)字符都去字庫(kù)讀取它的位圖,然后告訴Opengl去畫(huà),那顯然是很慢的。但如果將整個(gè)字庫(kù)放到Display List里,顯示字符時(shí)候只需要告訴Opengl這個(gè)字符的偏移量,OpenGL直接訪(fǎng)問(wèn)Display List,那就高效多了。

Pixel Data

      Pixle data 包括位圖(bitmap), Image, 和任何用于繪制的Pixel數(shù)據(jù)(比如Fonts)。通常是以矩陣的形式存放在內(nèi)存當(dāng)中。通過(guò)Pxiel data, 我們避免大量的圖形繪制命令。同時(shí)通過(guò)現(xiàn)實(shí)世界中獲取的紋理圖片,可以將最終的物體渲染得更逼真。比如說(shuō)畫(huà)一堵墻,如果沒(méi)有pixel data,我們需要將每塊磚頭都畫(huà)出來(lái),也就是說(shuō)需要大量的Vertex??墒侨绻ㄟ^(guò)一張現(xiàn)實(shí)生活中拍攝的磚墻的圖片,只需要4個(gè)點(diǎn)畫(huà)出一個(gè)大矩形,然后上面貼上紋理,顯然,速度和效果都要好得多。

FrameBuffer

      Framebuffer就是Opengl用來(lái)存儲(chǔ)結(jié)果的buffer。Opengl的frameBuffer類(lèi)型有幾種。Front Buffer 和 Back Buffer, 分別用于顯示和繪制,兩者通過(guò)swapBuffer 進(jìn)行交換。Left Buffer 和 Right buffer, 用于真立體(需要帶眼鏡的那種) 圖像的左右眼Buffer,Stencil buffer, 用于禁止在某些區(qū)域上進(jìn)行繪制,想像一下如果在一件T恤上印上圖案,你是不是需要一個(gè)鏤空的紙板?這個(gè)紙板就是stencil buffer.

OK, 對(duì)Opengl rendering pipeline簡(jiǎn)單介紹到此,有興趣的同學(xué)可以閱讀opengl的紅包書(shū)或運(yùn)行一些簡(jiǎn)單的例子來(lái)深入理解Opengl。回到主題,僅僅使用Opengl 和 GPU 取代Skia 就能夠大幅提升性能?答案當(dāng)然不是,性能的優(yōu)化很大程度上取決于應(yīng)用,應(yīng)用必須正確的使用Opengl命令才能發(fā)揮其最大效能。Android從pipeline 角度提供了兩種機(jī)制來(lái)提升性能,一個(gè)就是我們剛才說(shuō)到的Display List,另一個(gè)叫 Hardware Layer, 其實(shí)就是緩存的FrameBuffer, 比如說(shuō)Android的墻紙,一般來(lái)說(shuō),他是不會(huì)發(fā)生變化的,因此我們可以將它緩存在Hardware Layer里,這張就不需要每次進(jìn)行拷貝和重繪,從而大幅提升性能。

說(shuō)白了,優(yōu)化圖形性能的核心在于 1)用硬件來(lái)減少CPU的參與,加速圖形計(jì)算。 2)從軟件角度,通過(guò)Display List 和 Hardware Layer, 將已經(jīng)完成的工作盡可能的緩存起來(lái),只做必須要做的事情,盡可能的減少運(yùn)算量。

接下來(lái)看實(shí)現(xiàn)吧。

Canvas, Renderer, DisplayList, HardwareLayer 實(shí)現(xiàn)

這塊代碼相當(dāng)?shù)膹?fù)雜,花了兩天時(shí)間才把下面的圖整理出來(lái),但還是沒(méi)有把細(xì)節(jié)完全吃透,簡(jiǎn)單的介紹一下框架和流程吧,如果有需要大家可以下來(lái)細(xì)看代碼。  

 
 

 

圖中上半部為Java 代碼,下半部為Native層。先介紹里面出現(xiàn)的一些概念:

 Canvas

Canvas是Java層獨(dú)有的概念,它為View提供了大部分圖形繪制的接口。這個(gè)類(lèi)主要用于純軟件的繪制,硬件加速的圖形繪制則由HardwareCanvas取代。

HardwareCanvas,GLES20Canvas, GLES20RecordingCanvas

hardwareCanvas是一個(gè)抽象類(lèi),如果系統(tǒng)屬性和應(yīng)用程序指定使用硬件加速(現(xiàn)已成為默認(rèn)),它將會(huì)被View(通過(guò)AttachInfo,如 下圖所示) 引用來(lái)完成所有的圖形繪制工作。GLES20Canvas 則是hardwareCanvas的實(shí)現(xiàn),但它也只是一層封裝而已,真正的實(shí)現(xiàn)在Native 層,通過(guò)jni (andriod_view_gles20Canvas.cpp)接口來(lái)訪(fǎng)問(wèn)底層的Renderer, 進(jìn)而執(zhí)行OpenGL的命令。 此外,GLES20Canvas還提供了一些靜態(tài)接口,用于創(chuàng)建各類(lèi)Renderer對(duì)象。

GLES20RecordingCanvas 繼承GLES20Canvas, 通過(guò)它調(diào)用的OpenGL命令將會(huì)存儲(chǔ)在DisplayList里面,而不會(huì)立即執(zhí)行。

HardwareRenderer, GLRender, GL20Renderer

這三個(gè)類(lèi)都是Java的Wrapper類(lèi),通過(guò)訪(fǎng)問(wèn)各種Canvas來(lái)控制繪制流程。詳見(jiàn)下面兩張時(shí)序圖。

OpenGLRenderer, DisplayListRenderer, HardwareLayerRenderer

Java的HardwareCanvas 和 HardwareRenderer在底層的對(duì)應(yīng)實(shí)現(xiàn)。OpenGLRenderer是基類(lèi),只有它直接訪(fǎng)問(wèn)底層OpenGL庫(kù)。DisplayListRenderer 將View通過(guò)GLES20Canvas傳過(guò)來(lái)的OpenGL 命令存在OpenGL的DisplayList中。而HardwareLayerRenderer 管理HardwareLayer的資源。

GLES20
      就是OpenGL ES 2.0 的API。它的實(shí)現(xiàn)一般由GPU的設(shè)計(jì)廠(chǎng)家提供,可以在設(shè)備的/system/lib/egl/ 找到它的so,名字為 libGLES_xxx.so, xxx 就是特定設(shè)備的代號(hào),比如說(shuō),libGLES_gc.so 就是Vivante公司的GPU實(shí)現(xiàn),libGLESv2_mali.so 就是ARM公司提供的Mali GPU的實(shí)現(xiàn)。它也可以由軟件實(shí)現(xiàn),比如說(shuō) libGLES_android.so, 是Google提供的軟件實(shí)現(xiàn)。

EGL
      雖然對(duì)于上層應(yīng)用來(lái)說(shuō)OpenGL接口是跨平臺(tái)的,但是它的底層(GPU)實(shí)現(xiàn)和平臺(tái)(SoC)是緊密相關(guān)的,于是OpenGL組織定義一套接口用來(lái)訪(fǎng)問(wèn)平臺(tái)本地的窗口系統(tǒng)(native platform window system),這套接口就是EGL,比如說(shuō) eglCreateDisplay(), eglCreateSurface(), eglSwapBuffer()等等。EGL的實(shí)現(xiàn)一般明白libEGL.so, 放在/system/lib/egl/ 下面。

View, Canvas, Renderer, DisplayList, HardwareLayer 的關(guān)系如下圖所示:

每個(gè)View都對(duì)應(yīng)一個(gè)DisplayList, 在Native層代碼里管理。每個(gè)View通過(guò)GLESRecordingCanvas 以及Native層對(duì)應(yīng)的DisplayRenderer 將OpenGL命令存入DisplayList.最后View 通過(guò)GLES20Canvas 通知OpenGLRenderer 執(zhí)行這些DisplayList 里面的OpenGL 命令。

 

 他們的生命周期如下圖所示 (粉紅代表 New, 黑色代表 Delete, 黃色代表Java類(lèi),藍(lán)色代表C++, 綠色代表JNI).

 

  1. 如果系統(tǒng)支持硬件加速,ViewRootImpl首先創(chuàng)建一個(gè)GL20Renderer, 存在成員變量 mHardwareRenderer 里。
  2. Surafce是繪畫(huà)的基礎(chǔ),如果不存在,HardwareRenderer會(huì)調(diào)用GLRenderer->createEglSurface() 創(chuàng)建一個(gè)新的Surface。
  3. Surface創(chuàng)建好后,接著生成Canvas,因?yàn)榇蟛糠謶?yīng)用程序不會(huì)直接操作Surface。
  4. 在Canvas的構(gòu)造函數(shù)里,會(huì)依次創(chuàng)建Native層對(duì)應(yīng)的OpenGLRenderer對(duì)象,它會(huì)直接訪(fǎng)問(wèn)庫(kù) libGLES_xxx提供的OpenGL ES API,來(lái)負(fù)責(zé)整個(gè)View樹(shù)的繪制工作。
  5. 與此同時(shí),一個(gè)CanvasFinalizer 成員對(duì)象也會(huì)被創(chuàng)建,它保存剛剛創(chuàng)建出來(lái)的OpenGLRenderer 指針,當(dāng)它的finalizer()函數(shù)被調(diào)用是,負(fù)責(zé)將其銷(xiāo)毀,回收資源。
  6. 在運(yùn)行過(guò)程中,如果窗口死掉或者不在可見(jiàn),ViewRootImpl 會(huì)調(diào)用DestroyHardwareResource() 來(lái)釋放資源。這里會(huì)最終將底層創(chuàng)建的Hardware Layer回收。
  7. 同時(shí)Java端的GLES20Layer 對(duì)象也會(huì)因?yàn)楸毁x值 NULL 被GC在將來(lái)回收。
  8. 接下來(lái),ViewRootImpl調(diào)用 destroyHardwareRenderer() 將之前創(chuàng)建的Native Renderer(DisplayListRenderer,OpenGLRenderer)依次回收。
  9. 最后將Java 層的mHardwareRenderer 賦空,GC將會(huì)回收最開(kāi)始創(chuàng)建的GL20Renderer對(duì)象。支持,一個(gè)View樹(shù)的生命周期完成,所有資源清楚干凈。

等等!好像少了點(diǎn)什么,怎么沒(méi)有DisplayList? 前面不是說(shuō)它是性能優(yōu)化的幫手之一嗎?對(duì)了,上面只介紹了繪制的開(kāi)始和結(jié)尾,在View的生命周期中,還有最重要的一步,Draw 還沒(méi)有被介紹,DisplayList 相關(guān)的操作就是在Draw()里面完成的。

 Draw 流程

  繞了好大一圈,終于回到最初的話(huà)題,Android是怎樣將View畫(huà)出來(lái)的? 讓我們按照?qǐng)D中的序號(hào)一一進(jìn)行講解。(黃色:Java, 綠色:C++,藍(lán)色:JNI,粉色:New, 黑色:Delete).

 

  1. 首先,ViewRootImpl直接訪(fǎng)問(wèn)的HardwareRenderer 對(duì)象,首先在BeginFrame() 里獲取EGLDisplay(用于顯示) 和 初始化一個(gè)EGLSurface,OpenGL將在這個(gè)Surface上進(jìn)行繪圖。關(guān)于EGLDisplay 和 EGLSurface 將在 圖解Android - Android GUI 系統(tǒng) (3) - Surface Flinger 里詳細(xì)描述。
  2. 我們前面說(shuō)過(guò),Android 4.0 帶來(lái)的圖形性能的提升,有很大程度是DisplayList 帶來(lái)的,所以,HardwareRenderer接下來(lái)就通過(guò)buildDisplayList() 創(chuàng)建整個(gè)View樹(shù)的DisplayList. 最開(kāi)始,GL20Renderer為View生成了一個(gè)GLES20DisplayList, 這是一個(gè)影子類(lèi),沒(méi)有實(shí)際用途,主要用來(lái)管理Native層的DisplayList的銷(xiāo)毀。
  3. View 調(diào)用剛剛生成的GLES20DisplayList的 start() 方法,真正開(kāi)始構(gòu)建DisplayList的上下文。obtain() 函數(shù)里會(huì)判斷是否mCanvas 已經(jīng)存在,如果沒(méi)有則New 一個(gè)新的GLES20RecordingCanvas對(duì)象。
  4. 創(chuàng)建與GLES20RecordingCanvas 一一對(duì)應(yīng)的Native層的 DisplayListRenderer。
  5. 3,4是一個(gè)遞歸的過(guò)程,直到所有的View的DisplayList上下文生成,View才真正開(kāi)始Draw(), 這里,OpenGL命令(Op)不會(huì)被立即執(zhí)行,而是被存儲(chǔ)到剛剛生成的DisplayListRenderer里。
  6. 接著View調(diào)用GLESDisplayList的 end() 方法,這里Native層的DisplayList 對(duì)象才真正被創(chuàng)建出來(lái),Java 和 Native 的 DisplayList 對(duì)象一一對(duì)應(yīng)起來(lái)。
  7. end() 方法最后,調(diào)用GLES20RecordingCanvas.recycle() 方法,首先將Native的DisplayListRender 進(jìn)行重新初始化,然后將剛才創(chuàng)建出來(lái)的臨時(shí)對(duì)象賦NULL值(GLES20RecordingCanvas 和 GLES20DisplayList), 因?yàn)樗鼈兊氖姑呀?jīng)完成,將View的OpenGL命令存儲(chǔ)在Native層的DisplayList對(duì)象里。
  8. GC() 被調(diào)用后,GLES20RecordingCanvas 和 GLES20DisplayList 被釋放,相應(yīng)的Finalizer 對(duì)象方法會(huì)被調(diào)用,進(jìn)而調(diào)用Natice層的deleteDisplayListDefered(), 將之前不用的DisplayList 送入 Caches的Gabage 隊(duì)列中,等待回收。(這是在Native層實(shí)現(xiàn)的類(lèi)似Java GC的機(jī)制)
  9. 到此,所有的DisplayList 上下文準(zhǔn)備就緒。進(jìn)入preDraw 狀態(tài),在GL20Renderer的 onPreDraw() 方法里,最終調(diào)用到底層的clearGarbage將上一次繪圖操作的DisplayList在底層釋放。
  10. HardwareRenderer調(diào)用 GLES20Canvas 的drawDisplayList(), 通知 Native層的 OpenGLRenderer,其最終調(diào)用每個(gè)DisplayList的Replay() 方法執(zhí)行OpenGL命令。
  11. 所有OpenGL命令執(zhí)行完后, 圖形被繪制到第一步生成的EGLSurface, hardwareRender 調(diào)用 GLES20Canvas 的 eglSwapBuffers() 交換Buffer,交由SurfaceFlinger 在下一個(gè)VSync到來(lái)時(shí)進(jìn)行顯示。

Hardware Layer

即便是使用了DisplayList, 對(duì)于復(fù)雜的圖形,仍然需要執(zhí)行大量的OpenGL命令,如果需要對(duì)這一部分進(jìn)行優(yōu)化,就需要使用到 HardwareLayer對(duì)繪制的圖形進(jìn)行緩存,如果圖形不發(fā)生任何變化,就不需要執(zhí)行任何OpenGL命令,而是將之前緩存在GPU內(nèi)存的Buffer 直接與其他View進(jìn)行合成,從而大大的提高性能。這些存儲(chǔ)在GPU內(nèi)部的Buffer就稱(chēng)為 Hardware Layer。除了Hardware Layer, Android 還支持Software Layer,和Hardware Layer 不同之處在于,它不存在于GPU內(nèi)部,而是存在CPU的內(nèi)存里,因此它不經(jīng)過(guò)前面所說(shuō)的 Hardware Render Pipeline, 而是走Android最初的軟件Render pipeline。不管是Hardware Layer 還是 Software Layer, 在Draw() 內(nèi)部均稱(chēng)為Cache,只要有Cache的存在,相對(duì)應(yīng)的View將不用重繪,而是使用已有的Cache。Hardware Layer, Software Layer 和 Display List 是互斥的,同時(shí)只能有一種方法生效(當(dāng)然,Hardware Layer的第一次繪制還是通過(guò)Display List 完成),下表總結(jié)了它們的差別, 從中可以看到,Hardware Layer 對(duì)性能的提升是最大的,唯一的問(wèn)題是占用GPU的內(nèi)存(這也是為什么顯卡的內(nèi)存變得越來(lái)越大的原因之一),所以一般來(lái)說(shuō),Hardware Layer使用在那些圖片較為復(fù)雜,但不經(jīng)常改變,有動(dòng)畫(huà)操作或與其他窗口有合成的場(chǎng)景,比如說(shuō)WallPaper, Animation 等等。

 

  Enabled if GPU accelerated? Cached in

Performance(from Google I/O 2001)

Usage
Display List Hardware Accelerated = True Y GPU DisplayList 2.1 Complex View
Hardware Layer LayerType = HARDWARE Y GPU Memory 0.009 Complex View, Color Filter(顏色過(guò)濾), Alpha blending (透明度設(shè)置), etc. 
Software Layer LayerType = SOFTWARE N CPU Memory 10.3 No Hardware Accelerated, Color filter, Alpha blending, etc.

 

 

 

 

 

 

重繪 - Invaliate

前面介紹了View的第一次繪制的過(guò)程。但是一個(gè)View在運(yùn)行中終究是要發(fā)生變化的,比如說(shuō),用戶(hù)在TextView的文字發(fā)生了改變,或者動(dòng)畫(huà)導(dǎo)致View的尺寸發(fā)生變化,再或者說(shuō)一個(gè)對(duì)話(huà)框彈出然后又消失,被遮擋的部分重新露了出來(lái),這些都需要對(duì)View進(jìn)行重繪。在介紹重繪之前,我們先了解一下View內(nèi)部的一些Flag 定義。

 

Flags  == 1 Set at Clear at
PFFLAG_HAS_BOUNDS

1: View has size and Position set.
0: setFrame() was not called yet

View::setFrame()  
PFFLAG_DRAWN

1: Has been drawn, only after which, invalidate() is valid.
0: not drawn, need to draw() later to show it.

ViewGroup::addViewInLayout
ViewGroup::attachViewToParent
View::draw()
View::buildDrawingCache()
View::getHardwareLayer()
View::invalidate()
View::setLeft/Right/Top/Bottom()

View::invalidate()

PFFLAG_DRAWING_CACHE_VALID

1: Has DisplayList / Hardware Layer / Software Layer  
0: No Cache, using Software rendering path.

View::GetHardwareLayer()
View::GetDisplayList()

View::invalidate(true)
View::invalidate(rect)
View::invalidateChild()

PFFLAG_INVALIDATED   View is specifically invalidated, not just dirty(child for instance).
DisplayList will be recreated if set. 
ViewGroup::addViewInLayout
ViewGroup::attachViewToParent
View::force/requestLayout()
View::invalidate()

View::draw()
PFLAG_DIRTY   Set to indicate that the view need to be redrawn.
(use displaylist cache if PFFLAG_INVALIDATED flag is false)
View::invalidate()

ViewGroup::addViewInLayout
ViewGroup::attachViewToParent
View::draw()
View::buildDrawingCache()
View::getHardwareLayer()
View::invalidate()
View::setLeft/Right/Top/Bottom()
View::getDisplayList()

PFLAG_DIRTY_OPAQUE DIRTY because of OPAQUE (hidden by others). View::invalidateChild()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

從上表可以看出,View通過(guò)內(nèi)部這些Flag來(lái)控制重繪?;旧现乩L分兩種情況,一種是需要重新生成DisplayList, 另外一種是使用之前已有的Cache,包括DisplayList或者是Hardware Layer。使用哪種重繪方式由當(dāng)前View的Flags,以及應(yīng)用程序傳入的參數(shù)決定??刂扑木褪且唤MInvalidate() 函數(shù)。

 

復(fù)制代碼
void invalidate(boolean invalidateCache) {
        if (skipInvalidate()) { //如果View不可見(jiàn),并且不再動(dòng)畫(huà)退出過(guò)程中(fade out),將不執(zhí)行Invalidate().
            return;
        }
        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) || //DRAWN -> 已經(jīng)被Draw()過(guò)
            (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||  //有Cache,且被要求重新刷新Cache
            (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) //沒(méi)有正在Invalidate()中
        {
            mLastIsOpaque = isOpaque();
            mPrivateFlags &= ~PFLAG_DRAWN;
            mPrivateFlags |= PFLAG_DIRTY;
            if (invalidateCache) { 
                mPrivateFlags |= PFLAG_INVALIDATED; 
                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; //標(biāo)記將來(lái)清除Cache,如果為false,則有系統(tǒng)根據(jù)Dirty Region決定是否需要重新生成DisplayList。
            }
            final AttachInfo ai = mAttachInfo;
            final ViewParent p = mParent;
            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) { //系統(tǒng)不支持Dirty Region,必須重繪整個(gè)區(qū)域, 基本不會(huì)進(jìn)去
            }
            if (p != null && ai != null) {
                final Rect r = ai.mTmpInvalRect;
                r.set(0, 0, mRight - mLeft, mBottom - mTop);
                p.invalidateChild(this, r); //通知兄弟view(有共同的ViewParent(ViewGroup 或者 ViewRoot)進(jìn)行 Invalidate. 
            }
        }
    }
復(fù)制代碼

假如所有的條件都支持重繪,便會(huì)調(diào)用到ViewParent的invalidateChild()方法。(ViewParent是一個(gè)接口類(lèi),它的實(shí)現(xiàn)類(lèi)是ViewGroup 和 ViewRootImpl。)這個(gè)方法會(huì)從當(dāng)前View開(kāi)始,向上遍歷到ViewRoot 或者 到某個(gè)ViewGroup的區(qū)域與當(dāng)前View的Dirty區(qū)域沒(méi)有重疊為止。途中的每個(gè)ViewGroup都會(huì)被標(biāo)記上Dirty。在接下來(lái)VSYNC的performDraw()里,ViewRootImpl 會(huì)遍歷所有標(biāo)記Dirty的ViewGroup,然后找到里面標(biāo)記Dirty的View,只有這些View的DisplayList 被重建,而其他實(shí)際上沒(méi)有變化的View(雖然它們?cè)谕粋€(gè)ViewGroup里面),如果沒(méi)有Hardware Layer, 只需重新執(zhí)行對(duì)應(yīng)Display List 里面的OpenGL 命令。通過(guò)這種方式,Android只重繪需要重繪的View,從軟件層面將GPU的輸入最小化,從而優(yōu)化圖形性能。

 

4. Windows 的管理

到此,我們已經(jīng)了解了一個(gè)Acitivty(Window)是如何畫(huà)出來(lái)的,讓我們?cè)诤?jiǎn)要重溫一下這個(gè)過(guò)程:

  1. Acitivity創(chuàng)建, ViewRootImpl將窗口注冊(cè)到WindowManager Service,WindowManager Service 通過(guò)SurfaceFlinger 的接口創(chuàng)建了一個(gè)Surface Session用于接下來(lái)的Surface 管理工作。
  2. 由Surface Flinger 傳上來(lái)的VSYNC事件到來(lái),Choreographer 會(huì)運(yùn)行ViewRootImpl 注冊(cè)的Callback函數(shù), 這個(gè)函數(shù)會(huì)最終調(diào)用 performTraversal 遍歷View樹(shù)里的每個(gè)View, 在第一個(gè)VSYNC里,WindowManager Service 會(huì)創(chuàng)建一個(gè)SurafceControll 對(duì)象,ViewRootImpl 根據(jù)Parcel返回的該對(duì)象生成了Window對(duì)應(yīng)的Surface對(duì)象,通過(guò)這個(gè)對(duì)象,Canvas 可以要求Sruface Flinger 分配OpenGL繪圖用的Buffer。
  3. View樹(shù)里的每個(gè)View 會(huì)根據(jù)需要依次執(zhí)行 measure(),layout() 和 draw() 操作。Android 在3.0之后引入了硬件加速機(jī)制,為每個(gè)View生成DisplayList,并根據(jù)需要在GPU內(nèi)部生成Hardware Layer,從而充分利用GPU的功能提升圖形繪制速度。
  4. 當(dāng)某個(gè)View發(fā)生變化,它會(huì)調(diào)用invalidate() 請(qǐng)求重繪,這個(gè)函數(shù)從當(dāng)前View 出發(fā),向上遍歷找到View Tree中所有Dirty的 View 和 ViewGroup, 根據(jù)需要重新生成DisplayList, 并在drawDisplayList() 函數(shù)里執(zhí)行OpenGL命令將其繪制在某個(gè)Surface Buffer上。
  5. 最后,ViewRootImpl 調(diào)用 eglSwapBuffer 通知OpenGL 將繪制的Buffer 在下一個(gè)VSync點(diǎn)進(jìn)行顯示。

注意的是,上面討論的只是一個(gè)窗口的流程,而Android是個(gè)多窗口的系統(tǒng),窗口之間可能會(huì)有重疊,窗口切換會(huì)有動(dòng)畫(huà)產(chǎn)生,窗口的顯示和隱藏都有可能會(huì)導(dǎo)致資源的分配和釋放,這一切需要有一個(gè)全局的服務(wù)進(jìn)行統(tǒng)一的管理,這個(gè)服務(wù)就是我們大名鼎鼎的Window Manager Service (簡(jiǎn)寫(xiě) WMS).

其實(shí)Window Manager Service 的工作不僅僅是管理窗口,還會(huì)跟很多其他服務(wù)打交道,如 InputManager Service, AcitivityManager Service 等等,但本章只討論它在Window Manager 方面的工作,下圖中紅色標(biāo)記部分。

 Layout

 首先來(lái)看Layout。Layout 是Window Manager Service 重要工作之一,它的流程如下圖所示:

 

  • 每個(gè)View將期望窗口尺寸交給WMS(WindowManager Service).
  • WMS 將所有的窗口大小以及當(dāng)前的Overscan區(qū)域傳給WPM (WindowPolicy Manager).
  • WPM根據(jù)用戶(hù)配置確定每個(gè)Window在最終Display輸出上的位置以及需要分配的Surface大小。
  • 返回這些信息給每個(gè)View,他們將在給會(huì)的區(qū)域空間里繪圖。

Android里定義了很多區(qū)域,如下圖所示 

                                          

Overscan:
    Overscan 是電視特有的概念,上圖中黃色部分就是Overscan區(qū)域,指的是電視機(jī)屏幕四周某些不可見(jiàn)的區(qū)域(因?yàn)殡娨曁匦裕@部分區(qū)域的buffer內(nèi)容顯示時(shí)被丟棄),也意味著如果窗口的某些內(nèi)容畫(huà)在這個(gè)區(qū)域里,它在某些電視上就會(huì)看不到。為了避免這種情況發(fā)生,通常要求UI不要畫(huà)在屏幕的邊角上,而是預(yù)留一定的空間。因?yàn)镺verscan的區(qū)域大小隨著電視不 同而不同,它一般由終端用戶(hù)通過(guò)UI指定,(比如說(shuō)GoogleTV里就有確定Overscan大小的應(yīng)用)。

OverscanScreen, Screen: 
   
OverscanScreen 是包含Overscan區(qū)域的屏幕大小,而Screen則為去除Overscan區(qū)域后的屏幕區(qū)域, OverscanScreen > Screen.

Restricted and Unrestricted:
    某些區(qū)域是被系統(tǒng)保留的,比如說(shuō)手機(jī)屏幕上方的狀態(tài)欄(如圖紙綠色區(qū)域)和下方的導(dǎo)航欄,根據(jù)是否包括這些預(yù)留的區(qū)域,Android把區(qū)域分為Unrestricted Area 和 Resctrited Aread, 前者包括這部分預(yù)留區(qū)域,后者則不包含, Unrestricted area > Rectricted area。

mFrame, mDisplayFrame, mContainingFrame
   
Frame指的是一片內(nèi)存區(qū)域, 對(duì)應(yīng)于屏幕上的一塊矩形區(qū)域. mFrame的大小就是Surface的大小, 如上上圖中的藍(lán)色區(qū)域. mDisplayFrame 和 mContainingFrame 一般和mFrame 大小一致. mXXX 是Window(ViewRootImpl, Windowstate) 里面定義的成員變量.

mContentFrame, mVisibleFrame
   
一個(gè)Surface的所有內(nèi)容不一定在屏幕上都得到顯示, 與Overscan重疊的部分會(huì)被截掉, 系統(tǒng)的其他窗口也會(huì)遮擋掉部分區(qū)域 (比如短信窗口,ContentFrame是800x600(沒(méi)有Status Bar), 但當(dāng)輸入法窗口彈出是,變成了800x352), 剩下的區(qū)域稱(chēng)為Visible Frame, UI內(nèi)容只有畫(huà)在這個(gè)區(qū)域里才能確保可見(jiàn). 所以也稱(chēng)為Content Frame. mXXX也是Window(ViewRootImpl, WindowState) 里面定義的成員變量.

Insects
   
insets的定義如上圖所示, 用了表示某個(gè)Frame的邊緣大小.

Layout 在WMS 內(nèi)部的時(shí)序如下圖所示,外部調(diào)整Overscan參數(shù)或View內(nèi)部主動(dòng)調(diào)用requestLayout() 都會(huì)觸發(fā)WMS的重新layout,layout完成后,WMS會(huì)通過(guò)IWindow的resized()接口通知ViewRoot, 最終會(huì)調(diào)用requestLayout(), 并在下一個(gè)VSYNC 事件到來(lái)時(shí)更新。

。

 計(jì)算Layout主要有圖中三個(gè)紅色的函數(shù)完成,它們代碼很多,涉及到很多計(jì)算,但只要對(duì)著我們上面給的三個(gè)圖來(lái)看,不難看出它的意思,本文將不詳細(xì)深入。

Animation

Animation的原理很簡(jiǎn)單,就是定時(shí)重繪圖形。下面的類(lèi)圖中給出了Android跟Animation相關(guān)的類(lèi)。

Animation:
    Animation抽象類(lèi),里面最重要的一個(gè)接口就是applyTranformation, 它的輸入是當(dāng)前的一個(gè)描述進(jìn)度的浮點(diǎn)數(shù)(0.0 ~ 1.0), 輸出是一個(gè)Transformation類(lèi)對(duì)象,這個(gè)對(duì)象里有兩個(gè)重要的成員變量,mAlpha 和 mMatrix, 前者表示下一個(gè)動(dòng)畫(huà)點(diǎn)的透明度(用于灰度漸變效果),后者則是一個(gè)變形矩陣,通過(guò)它可以生成各種各樣的變形效果。Android提供了很多Animation的具體實(shí)現(xiàn),比如RotationAnimation, AlphaAnimation 等等,用戶(hù)也可以實(shí)現(xiàn)自己的Animation類(lèi),只需要重載applyTransform 這個(gè)接口。注意,Animation類(lèi)只生成繪制動(dòng)畫(huà)所需的參數(shù)(alpha 或 matrix),不負(fù)責(zé)完成繪制工作。完成這個(gè)工作的是Animator.

Animator:
   
控制動(dòng)畫(huà)的‘人’, 它通常通過(guò)向定時(shí)器Choreographer 注冊(cè)一個(gè)Runnable對(duì)象來(lái)實(shí)現(xiàn)定時(shí)觸發(fā),在回調(diào)函數(shù)里它要做兩件事情:1. 從Animation那里獲取新的Transform, 2. 將Transform里的值更新底層參數(shù),為接下來(lái)的重繪做準(zhǔn)備。動(dòng)畫(huà)可以發(fā)生在Window上,也可以發(fā)生在某個(gè)具體的View。前者的動(dòng)畫(huà)會(huì)通過(guò)SurfaceControl直接在某個(gè)Surface上進(jìn)行操作(會(huì)在SurfaceFlinger里詳細(xì)描述),比如設(shè)置Alpha值。后者則通過(guò)OpenGL完成(生成我們前面提過(guò)的DisplayList).

WindowStateAnimator, WindowAnimator,  AppWindowAnimator:
   
針對(duì)不同對(duì)象的Animator. WindowAnimator, 負(fù)責(zé)整個(gè)屏幕的動(dòng)畫(huà),比如說(shuō)轉(zhuǎn)屏,它提供Runnable實(shí)現(xiàn)。WindowStateAnimator, 負(fù)責(zé)ViewRoot,即某一個(gè)窗口的動(dòng)畫(huà)。AppWindowAnimator, 負(fù)責(zé)應(yīng)用啟動(dòng)和退出時(shí)候的動(dòng)畫(huà)。這幾個(gè)Animator都會(huì)提供一個(gè)函數(shù),stepAnimationLocked(), 它會(huì)完成一個(gè)動(dòng)畫(huà)動(dòng)作的一系列工作,從計(jì)算Transformation到更新Surface的Matrix.

 

具體來(lái)看一下Window的Animation和View的Animation

  1. WindowManagerService 的 scheduleAnimationLocked() 將windowAnimator的mAnimationRunnable 注冊(cè)到定時(shí)器 Choreographer.
  2. 如果應(yīng)用程序的res/anim/下有xml文件定義animation,在layout過(guò)程中,會(huì)通過(guò)appTransition類(lèi)的loadAnimation() 函數(shù)將XML轉(zhuǎn)換成 Animation_Set 對(duì)象,它里面可以包含多個(gè)Animation。
  3. 當(dāng)下一個(gè)VSYNC事件到來(lái),剛才注冊(cè)的Callback函數(shù)被調(diào)用,即WindowAnimator的mAnimationRunnable,里面調(diào)用 animateLocked(), 首先,打開(kāi)一個(gè)SurfaceControl的動(dòng)畫(huà)會(huì)話(huà),animationSession。
  4. 首先執(zhí)行的動(dòng)畫(huà)是 appWindowAnimator, 如果剛才loadAnimation() 返回的animation不為空,便會(huì)走到Animation的getTransform() 獲取動(dòng)畫(huà)的參數(shù),這里可能會(huì)同時(shí)有多個(gè)動(dòng)畫(huà)存在,通過(guò)Transform的compose()函數(shù)將它們最終合為一個(gè)。
  5. 接下來(lái)上場(chǎng)的是DisplayContentsAnimator, 它主要用來(lái)實(shí)現(xiàn)灰度漸變和轉(zhuǎn)屏動(dòng)畫(huà)。同樣,首先通過(guò)stepAnimation() 獲取動(dòng)畫(huà)變形參數(shù),然后通過(guò)SurfaceControl將其更新到SrufaceFlinger內(nèi)部對(duì)應(yīng)的Layer. 這里首先完成的是轉(zhuǎn)屏的動(dòng)畫(huà)
  6. 然后就是每個(gè)窗口的動(dòng)畫(huà)。后面跟著的 perpareSurfaceLocked() 則會(huì)更新參數(shù)。
  7. Wallpaper的動(dòng)畫(huà)。
  8. 接下來(lái),就是上面提到的DisplayContentsAnimator的第二部分,通過(guò)DimLayer實(shí)現(xiàn)漸變效果。
  9. Surface的控制完成后,關(guān)閉對(duì)話(huà)。然后scheduleAnimationLocked() 規(guī)劃下一步動(dòng)畫(huà)。
  10. 接下來(lái)的performDraw()會(huì)把所有更新參數(shù)的View,或Surface交給OpenGL或HWcomposer進(jìn)行處理,于是我們就看到了動(dòng)畫(huà)效果。

 View 的動(dòng)畫(huà)實(shí)現(xiàn)步驟與Windows 類(lèi)似,有興趣的同學(xué)可以去看View.java 的 drawAnimation() 函數(shù)。

 管理窗口

WMS 里面管理著各式各樣的窗口, 如下表所示(在WindowManagerService.java 中定義)

   類(lèi)型 用途
mAnimatingAppToken   ArrayList<AppWindowToken> 正在動(dòng)畫(huà)中的應(yīng)用
mExistingAppToken ArrayList<AppWindowToken> 退出但退出動(dòng)畫(huà)還沒(méi)有完成的應(yīng)用。
mResizingWindows ArrayList<WindowState> 尺寸正在改變的窗口,當(dāng)改變完成后,需要通知應(yīng)用。
mFinishedStarting ArrayList<AppWindowToken> 已經(jīng)完成啟動(dòng)的應(yīng)用。
mPendingRemove ArrayList<WindowState> 動(dòng)畫(huà)結(jié)束的窗口。
mLosingFocus  ArrayList<WindowState>  失去焦點(diǎn)的窗口,等待獲得焦點(diǎn)的窗口進(jìn)行顯示。
mDestorySurface    ArrayList<WindowState> 需要釋放Surface的窗口。
mForceRemoves  ArrayList<WindowState> 需要強(qiáng)行關(guān)閉的窗口,以釋放內(nèi)存。
mWaitingForDrawn ArrayList<Pair<WindowState, IRemoteCallback>> 等待繪制的窗口
mRelayoutWhileAnimating ArrayList<WindowState> 請(qǐng)求relayout但此時(shí)仍然在動(dòng)畫(huà)中的窗口。
mStrictModeFlash StrictModeFlash 一個(gè)紅色的背景窗口,用于提示可能存在的內(nèi)存泄露。
mCurrentFocus   WindowState 當(dāng)前焦點(diǎn)窗口
mLastFocus WindowState 上一焦點(diǎn)窗口
mInputMethodTarget WindowState 輸入法窗口下面的窗口。
mInputMethodWindow  WindowState 輸入法窗口
mWallpaperTarget WindowState 墻紙窗口
mLowerWallpaperTarget WindowState 墻紙切換動(dòng)畫(huà)過(guò)程中Z-Order 在下面的窗口
mHigherWallpaperTarget WindowState 墻紙切換動(dòng)畫(huà)過(guò)程中Z-Order 在上面的窗口
     
     

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

可以看到這里大量的用到了隊(duì)列,不同的窗口,或同一窗口在不同的階段,可能會(huì)出現(xiàn)在不同的隊(duì)列里。另外因?yàn)閃indowManager Service 的服務(wù)可能被很多個(gè)線(xiàn)程同時(shí)調(diào)用,在這種復(fù)雜的多線(xiàn)程環(huán)境里,通過(guò)鎖來(lái)實(shí)現(xiàn)線(xiàn)程安全非常難以實(shí)現(xiàn),一不小心就可能導(dǎo)致死鎖,所以在 WindowManager 內(nèi)專(zhuān)門(mén)有一個(gè)執(zhí)行線(xiàn)程(WM Thread)來(lái)將所有的服務(wù)請(qǐng)求通過(guò)消息進(jìn)行異步處理,實(shí)現(xiàn)調(diào)用的序列化。隊(duì)列是實(shí)現(xiàn)異步處理的常用手段。隊(duì)列加Looper線(xiàn)程是Android 應(yīng)用常用的設(shè)計(jì)模型。

此外,WindowManager還根據(jù)Window的類(lèi)型進(jìn)行了分類(lèi)(在WindowManager.java),如下表,

類(lèi)型 常量范圍 子類(lèi) 常量值 說(shuō)明 例子
APPLICATION_WINDOW 1~99 TYPE_BASE_APPLICATION 1     
    TYPE_APPLICATION 2  應(yīng)用窗口  大部分的應(yīng)用程序窗口
    TYPE_APPLICATION_STARTING 3  應(yīng)用程序的Activity顯示之前由系統(tǒng)顯示的窗口  
    LAST_APPLICATION_WINDOW  99    
SUB_WINDOW 1000~1999 FIRST_SUB_WINDOW 1000    
    TYPE_APPLICATION_PANEL 1000  顯示在母窗口之上,遮擋其下面的應(yīng)用窗口。  
    TYPE_APPLICATION_MEDIA 1001  顯示在母窗口之下,如果應(yīng)用窗口不挖洞,即不可見(jiàn)。 SurfaceView,在小窗口顯示時(shí)設(shè)為MEDIA, 全屏顯示時(shí)設(shè)為PANEL
    TYPE_APPLICATION_SUB_PANEL 1002         
    TYPE_APPLICATION_ATTACHED_DIALOG 1003    
    TYPE_APPLICATION_MEIDA_OVERLAY 1004  用于兩個(gè)SurfaceView的合成,如果設(shè)為MEDIA,
則上面的SurfaceView 擋住下面的SurfaceView
 
SYSTEM_WINDOW   2000~2999 TYPE_STATUS_BAR   2000 頂部的狀態(tài)欄  
    TYPE_SEARCH_BAR 2001 搜索窗口,系統(tǒng)中只能有一個(gè)搜索窗口  
    TYPE_PHONE 2002  電話(huà)窗口  
    TYPE_SYSTEM_ALERT 2003 警告窗口,在所有其他窗口之上顯示   電量不足提醒窗口
    TYPE_KEYGUARD 2004 鎖屏界面  
    TYPE_TOAST 2005 短時(shí)的文字提醒小窗口  
    TYPE_SYSTEM_OVERLAY 2006 沒(méi)有焦點(diǎn)的浮動(dòng)窗口  
    TYPE_PRIORITY_PHONE 2007 緊急電話(huà)窗口,可以顯示在屏保之上  
    TYPE_SYSTEM_DIALOG   2008 系統(tǒng)信息彈出窗口  比如SIM插上后彈出的運(yùn)營(yíng)商信息窗口
    TYPE_KEYGUARD_DIALOG 2009 跟KeyGuard綁定的彈出對(duì)話(huà)框 鎖屏?xí)r的滑動(dòng)解鎖窗口
    TYPE_SYSTEM_ERROR 2010 系統(tǒng)錯(cuò)誤提示窗口  ANR 窗口
    TYPE_INPUT_METHOD 2011 輸入法窗口,會(huì)擠占當(dāng)前應(yīng)用的空間  
    TYPE_INPUT_METHOD_DIALOG 2012 彈出的輸入法窗口,不會(huì)擠占當(dāng)前應(yīng)用窗口空間,在其之上顯示  
    TYPE_WALLPAPER 2013  墻紙  
    TYPE_STATUS_BAR_PANEL 2014 從狀態(tài)條下拉的窗口  
    TYPE_SECURE_SYSTEM_OVERLAY 2015 只有系統(tǒng)用戶(hù)可以創(chuàng)建的OVERLAY窗口  
    TYPE_DRAG 2016 浮動(dòng)的可拖動(dòng)窗口 360安全衛(wèi)士的浮動(dòng)精靈
    TYPE_STATUS_BAR_PANEL 2017    
    TYPE_POINTER 2018 光標(biāo)  
    TYPE_NAVIGATION_BAR 2019    
    TYPE_VOLUME_OVERLAY 2020 音量調(diào)節(jié)窗口  
    TYPE_BOOT_PROGRESS 2021 啟動(dòng)進(jìn)度,在所有窗口之上  
    TYPE_HIDDEN_NAV_CONSUMER 2022 隱藏的導(dǎo)航欄  
    TYPE_DREAM 2023 屏保動(dòng)畫(huà)  
    TYPE_NAVIGATION_BAR_PANEL 2024 Navigation bar 彈出的窗口 比如說(shuō)應(yīng)用收集欄
    TYPE_UNIVERSAL_BACKGROUND   2025    
    TYPE_DISPLAY_OVERLAY 2026 用于模擬第二顯示設(shè)備  
    TYPE_MAGNIFICATION 2027 用于放大局部  
    TYPE_RECENTS_OVERLAY 2028 當(dāng)前應(yīng)用窗口,多用戶(hù)情況下只顯示在用戶(hù)節(jié)目  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

windowManager Service 會(huì)根據(jù)窗口的類(lèi)型值來(lái)決定Z-Order (于常量值無(wú)關(guān),值大說(shuō)明是后面Android版本添加的,比如說(shuō)2025~2028就是4.3 新加的)。比如說(shuō)SurfaceView.java 里的一個(gè)函數(shù),

復(fù)制代碼
    public void setZOrderOnTop(boolean onTop) {
        if (onTop) {
            mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; //PANEL在上面
            // ensures the surface is placed below the IME
            mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
        } else {
            mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; //MEDIA類(lèi)型窗口在應(yīng)用窗口之下,應(yīng)用必需挖洞(設(shè)Alpha值)才能露出它。
            mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
        }
    }
復(fù)制代碼

這些類(lèi)型最終在WindowManager 內(nèi)部轉(zhuǎn)換成幾個(gè)Z-Order 值,mBaseLayer, mSubLayer, mAnimationLayer, 分別表明主窗口,子窗口(附加在主窗口之上),和動(dòng)畫(huà)窗口的Z-Order值(越大越在上邊)。不同的窗口類(lèi)型在不同的硬件產(chǎn)品上有不同的定義,因此它是實(shí)現(xiàn)在WindowManagerPolicy里的windowTypeToLayerLw(), 舉PhoneWindowManager 為例,它的ZOrder 順序是:

Univese background < Wallpaper < Phone < Search Bar < System Dialog < Input Method Window < Keyguard < Volume < System Overlay < Navigation < System Error <  < Display Overlay< Drag < Pointer < Hidden NAV consumer, 

所以,我們?nèi)绻谑謾C(jī)鎖屏?xí)r顯示歌曲播放進(jìn)度,就必須給這個(gè)窗口分配一個(gè)大于Keyguard的type,如 system overlay 等。

一個(gè)Window可以有若干個(gè)Sub Window, 他們和主窗口的ZOrder關(guān)系是

Media Sublayer(-2) < Media Overlay sublayer (-1) < Main Layer(0) < Attached Dialog (1) < Sub panel Sublayer (2)

通過(guò) "adb shell dumpsys window" 可以查看系統(tǒng)當(dāng)前運(yùn)行的窗口的ZOrder 和 Visibility, 比如下面就是在短信輸入界面下運(yùn)行“dumpsys" 獲得的結(jié)果,

復(fù)制代碼
   1  Window #0 Window{4ea4e178 u0 Keyguard}:
   2     mBaseLayer=121000 mSubLayer=0 mAnimLayer=121000+0=121000 mLastLayer=121000
   3     mViewVisibility=0x8 mHaveFrame=true mObscured=false
   4   Window #1 Window{4ea4aa7c u0 InputMethod}:
   5     mBaseLayer=101000 mSubLayer=0 mAnimLayer=21020+0=21020 mLastLayer=21020
   6     mViewVisibility=0x0 mHaveFrame=true mObscured=false
   7   Window #2 Window{4ec1a150 u0 com.android.mms/com.android.mms.ui.ComposeMessageActivity}:
   8     mBaseLayer=21000 mSubLayer=0 mAnimLayer=21015+0=21015 mLastLayer=21015
   9     mViewVisibility=0x0 mHaveFrame=true mObscured=false
  10   Window #3 Window{4ea7c714 u0 com.android.mms/com.android.mms.ui.ConversationList}:
  11     mBaseLayer=21000 mSubLayer=0 mAnimLayer=21010+0=21010 mLastLayer=21015
  12     mViewVisibility=0x8 mHaveFrame=true mObscured=true
  13   Window #4 Window{4eaedefc u0 com.android.launcher/com.android.launcher2.Launcher}:
  14     mBaseLayer=21000 mSubLayer=0 mAnimLayer=21005+0=21005 mLastLayer=21010
  15     mViewVisibility=0x8 mHaveFrame=true mObscured=true
  16   Window #5 Window{4ea17064 u0 jackpal.androidterm/jackpal.androidterm.Term}:
  17     mBaseLayer=21000 mSubLayer=0 mAnimLayer=21000+0=21000 mLastLayer=22000
  18     mViewVisibility=0x8 mHaveFrame=true mObscured=true
復(fù)制代碼

可以看到:

  1. 當(dāng)前只有兩個(gè)窗口可見(jiàn), InputMethod 和 com.android.mms/com.android.mms.ui.ComposeMessageActivity, mViewVisibility = 0 (0在View.java定義是可見(jiàn)), 而其他 mViewVisibility=0x8 (定義在View.java里, 意思是”GONE").
  2. InputMethod(mLastLayer=21020) 在 ComposeMessageActivity(mLastLayer=21015) 之上. 細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn),InputMethod的mBaseLayer = 101000,為什么mLastLayer小那么多?因?yàn)閙LastLayer才是真正的z-order, 它經(jīng)過(guò)了WidowManager的調(diào)整。當(dāng)用戶(hù)點(diǎn)擊輸入框,View會(huì)通過(guò)InputMethodManager 發(fā)送一個(gè)showSoftInput命令,經(jīng)過(guò)InputManagerService的處理,輸入法窗口(KeyboardView)會(huì)被加入到WndowManager Service里,WindowManager Service 會(huì)尋找它的目標(biāo)窗口, 即需要輸入的窗口,(遍歷WindowList 然后根據(jù)窗口的Flags判斷),然后將輸入法窗口的mLayer值改為 目標(biāo)窗口的mLayer + 5,這樣,輸入法窗口就顯示在了目標(biāo)窗口之上。在這里,輸入法窗口存在于InputMethodManagerService 的上下文里,而不是某個(gè)Activity,所以他可以跟任何需要輸入法的Activity綁定。其他一些應(yīng)用,比如說(shuō)PiP(三星的Galaxy S3可以在一個(gè)浮動(dòng)的小窗口里顯示視頻)也是運(yùn)用了類(lèi)似的方法來(lái)實(shí)現(xiàn)的。Android的輸入法是一個(gè)非常值得研究的模塊,留到后面探討。

所以,WindowManager Service 是通過(guò)調(diào)整窗口的mViewVisibility 和 mLayer 值來(lái)實(shí)現(xiàn)窗口重疊。最后給出跟Z-order相關(guān)的類(lèi)圖。

 

 圖中序號(hào)表示輸入法窗口找到它的目標(biāo)窗口的過(guò)程:

  1. WindowManagerService 找到默認(rèn)輸出(Default Display) 的DisplayContents成員變量。
  2. 里面有一個(gè)數(shù)組WindowList-mWindows, 按照Z(yǔ)-Order順序保存了當(dāng)前在這個(gè)Display上輸出的所有窗口WindowState。
  3. 遍歷所有的WindowState,判斷它的mAppToken是否和輸入法窗口的mAppToken一致。呼起輸入法窗口的窗口會(huì)將自己的mAppToken拷貝給它。
  4. 相同的Token下,可能有多個(gè)窗口,通過(guò)WindowToken.windows 或者 AppWindowToken.allAppWindows, 可以找到他們。

 

WindowManager Service的介紹暫告一段落,它與其他重要的Service,SurfaceFlinger, ActivityManager, InputManager, PowerManager, WatchDog 之間的關(guān)系將在其他文章介紹。

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多