天天看點

Android繪制流程一、前言二、Android消息流與Activity中xml布局檔案的解析三、Android繪制流程四、其他遺留問題:

  mfc、wtl、duilib、qt、skia、opengl。

android裡面的畫圖分為2d和3d兩種: 2d是由skia 來實作的,3d部分是由opengl實作的。

視窗

  對使用者來說, 視窗就是手機螢幕, 包括下面的那些home、back按鍵、狀态欄等。對于activity來說, 視窗就是除系統狀态欄和系統按鍵的螢幕區域, 有window之類的概念。對于wms來說, 它沒有什麼視窗的概念, 它能接受的隻是一個個view而已。也就是activity這裡還有window這個概念, 但在wms那裡, 已經沒有window的概念了。 視窗類型分為應用程式視窗: 就是一般應用程式的視窗, 比如我們應用程式的activity的視窗。子視窗: 一般在activity裡面的視窗, 比如tabactivity。系統視窗: 系統的視窗, 比如輸入法、toast、牆紙等等…系統視窗不需要對應任何activity, 也不需要有父視窗, 對于應用程式而言, 理論上是無法建立系統視窗的, 因為所有的應用程式都沒有這個權限, 然而系統程序卻可以建立系統視窗。windowmanager.layoutparams裡面有關于各種視窗的type類型定義, type還有個含義就是視窗的z-order, 值越大, 顯示的位置越在上面。

window、phonewindow

  頂層視窗樣式和行為的抽象類, 概括了android視窗的基本屬性和基本功能。該類執行個體的getdecorview()方法傳回的decorview被用來作為頂層視圖添加到wm中。 建立時機: activitythread.handlelaunchactivity ---> activitythread.performlaunchactivity --->activity.attach

windowmanager、windowmanagerimpl、windowmanagerglobal

  與一個特定的display相關聯, windowmanager主要用來管理視窗的一些狀态、屬性、view增加、删除、更新、視窗順序、消息收集和處理等。它面向的對象一端是螢幕, 另一端就是 view , 直接忽略我們以前的 activity 或者 dialog 之類的東東。windowmanager是一個接口類, 其真正的實作是windowmanagerimpl, 後者同時也是整個應用程式中所有window的管理者。

activity

  activity是支援顯示ui的, 但不直接管理view樹或者viewroot, activity并沒有與這兩者産生直接的聯系, 是通過中間 “window”的對象。 建立過程: 1>、 使用代理模式啟動到activitymanagerservice中執行; 2>、 建立activityrecord到mhistory記錄中; 3>、 通過socket通信到zgote相關類建立process; 4>、通過applicatonthread與activitymanagerservice建立通信; 5>、activitymanagerservice通知activethread啟動activity的建立; 6>、activitythread建立activity加入到mactivities中并開始排程activity執行; 7>、activitythread.handlelaunchactivity ---> activitythread.performlaunchactivity
Android繪制流程一、前言二、Android消息流與Activity中xml布局檔案的解析三、Android繪制流程四、其他遺留問題:

</blockquote>

viewroot、viewrootimpl

  任何顯示在裝置中的視窗如: activity、dialog等, 都包含一個viewroot執行個體。viewroot可以被了解為“view樹的管理者”, viewroot中的mview成員變量指向的就是它所管理的view樹的根。viewroot的核心任務就是與windowmanagerservice進行通信, 從viewrootimpl到wms間的通信利用的是iwindowsession, 而反方向則是由iwindow來完成的。viewroot與viewrootimpl的功能是一樣的, 隻不過是android不同版本的不同稱呼。 建立時機: activitythread.handleresumeactivity ---&gt; windowmanager.addview---&gt; windowmanagerglobal.addview添加一個view到vm中時, 與添加的view執行個體一一對應。

acitivitymanagerservice

  ams提供了一個arraylist mhistory來管理所有的activity, activity在ams中的形式是activityrecord, task在ams中的形式為taskrecord, 程序在ams中的管理形式為processrecord。是個獨立的系統服務程序。

activitythread

  管理應用程序的主線程的執行(相當于普通java程式的main入口函數), 并根據ams的要求(通過iapplicationthread接口, ams為client、activitythread.applicationthread為server)負責排程和執行activities、broadcasts和其它操作。activitythread是每一個應用程式所在程序的主線程, 循環消息處理。activitythread與acitivitymanagerservice的通信是屬于程序間通信, 使用binder機制;

windowmanagerservice

  對系統中的所有視窗進行管理。windowmanager是運作在application process中的, windowmanagerservice是在system_server程序中運作, 兩者的通信是通過中間的會話層iwindowsession來進行的。

附:相關簡化類結構

  wms收到使用者消息後需要把消息派發到視窗, view類本身并不能直接接收wms傳遞過來的消息, 真正接收使用者消息的必須是iwindow類, 而實作iwindow類的是viewroot.w類。 觸屏消息 ----&gt; windowmanagerservice ----&gt; viewroot ----&gt; decor view ----&gt; activity ----&gt; 傳遞給指定的view。
  用來儲存xml中每個控件的屬性值。view通過layoutparams類告訴其父視圖它想要的大小(即, 長度和寬度), 是以, 每個view都包含一個viewgroup.layoutparams類或者其派生類。
Android繪制流程一、前言二、Android消息流與Activity中xml布局檔案的解析三、Android繪制流程四、其他遺留問題:

  layoutinflater利用xml解析器将布局檔案解析成一個完整的view樹, 所有xxx.xml的布局檔案都需要解析成一個完整的view樹。

  從上面得知, 我們将view的attributeset屬性傳遞給generatelayoutparams()方法, 讓其建構合适地layoutparams對象,并且初始化屬性值weight和height。但更重要的是, viewgroup的子類可以重載generatelayoutparams方法, 傳回特定的layoutparams對象, 例如: 對于linearlayout而言, 則是linearlayout.layoutparams對象。
  我們知道activity中的phonewindow對象會建立了一個decorview(父類為framelayout)視窗頂層視圖, 然後通過layoutinflater将xml内容布局解析成view樹形結構添加到decorview頂層視圖中id為content的framelayout父容器上面。到此, 我們已經知道activity的content内容布局最終會添加到decorview視窗頂層視圖上面。那麼, decorview是怎麼添加到視窗的呢?這時候我們不得不從activity是怎麼啟動的說起, 當activity初始化 window和将布局添加到phonewindow的内部類decorview類之後, activitythread類會調用handleresumeactivity方法将頂層視圖decorview添加到視窗上。

handlerresumeactivity方法的實作:

windowmanagerimpl 中addview方法:

windowmanagerglobal 中addview方法:

viewrootimpl中setview的方法:

Android繪制流程一、前言二、Android消息流與Activity中xml布局檔案的解析三、Android繪制流程四、其他遺留問題:
  view系統的繪制流程會從viewrootimpl的performtraversals()方法中開始, 每一個視圖的繪制過程都必須經曆三個最主要的階段onmeasure()、onlayout()和ondraw()。
Android繪制流程一、前言二、Android消息流與Activity中xml布局檔案的解析三、Android繪制流程四、其他遺留問題:
  measure函數的作用是為整個view樹計算實際的大小, 設定每個view對象的布局大小(“視窗”大小)。實際對應屬性就是view中的mmeasuredheight(高)和mmeasurewidth(寬)。方法中參數widthmeasurespec和heightmeasurespec, 這兩個值分别用于确定視圖的寬度和高度的規格和大小。 measurespec的值由specsize和specmode共同組成的, 其中specsize記錄的是大小, specmode記錄的是規格。 exactly 表示父視圖希望子視圖的大小應該是由specsize的值來決定的。子元素将被限定在給定的邊界裡而忽略它本身大小; at_most 表示子視圖最多隻能是specsize中指定的大小, 開發人員應該盡可能小得去設定這個視圖, 并且保證不會超過specsize。 unspecified 表示開發人員可以将視圖按照自己的意願設定成任意的大小, 沒有任何限制。這種情況比較少見, 不太會用到。

view中的方法:

  measure()這個方法是final的, 是以我們無法在子類中去重寫這個方法, 說明android是不允許我們改變view的measure架構的。然後在第9行調用了onmeasure()方法, 這裡才是真正去測量并設定view大小的地方。之後會在onmeasure()方法中調用setmeasureddimension()方法來設定測量出的大小, 這樣一次measure過程就結束了。 當然, 一個界面的展示可能會涉及到很多次的measure, 因為一個布局中一般都會包含多個子視圖,每個視圖都需要經曆一次measure過程。由父視圖在onmeasure中循環調用viewgroup中的measurechildwithmargins實作子視圖的measure過程。

framelayout中方法:

viewgroup中的方法:

  viewrootimpl的performtraversals()方法會在measure結束後繼續執行, 為視圖進行布局的, 也就是确定視圖的位置。并調用view的layout()方法來執行此過程。 viewrootimpl中的方法

可以看到, 這裡還把剛才測量出的寬度和高度傳到了layout()方法中.</blockquote>

  layout()方法接收四個參數, 分别代表着左、上、右、下的坐标, 當然這些坐标是相對于目前視圖的父視圖而言的。在layout()方法中, 首先會調用setframe()方法來判斷視圖的大小是否發生過變化, 以确定有沒有必要對目前的視圖進行重繪, 同時還會在這裡把傳遞過來的四個參數分别指派給mleft、mtop、mright和mbottom這幾個變量。 view中的onlayout()方法就是一個空方法, 因為onlayout()過程是為了确定視圖在布局中所在的位置, 而這個操作應該是由布局來完成的, 即父視圖決定子視圖的顯示位置。

viewgroup中的方法

  viewgroup中的onlayout()方法是一個抽象方法, 這就意味着所有viewgroup的子類都必須重寫這個方法。在onlayout()過程結束後, 我們就可以調用getwidth()方法和getheight()方法來擷取視圖的寬高了。   getwidth()方法和getmeasurewidth()方法到底有什麼差別? getmeasurewidth()方法在measure()過程結束後就可以擷取到了, 而getwidth()方法要在layout()過程結束後才能擷取到。另外, getmeasurewidth()方法中的值是通過setmeasureddimension()方法來進行設定的, 而getwidth()方法中的值則是通過視圖右邊的坐标減去左邊的坐标計算出來的。
  measure和layout的過程都結束後, 接下來就進入到draw的過程了。
Android繪制流程一、前言二、Android消息流與Activity中xml布局檔案的解析三、Android繪制流程四、其他遺留問題:

viewrootimpl裡的方法

  ondraw為空方法, 因為每個視圖的内容部分肯定都是各不相同的, 這部分的功能需交給子類去實作。dispatchdraw這一步的作用是對目前視圖的所有子視圖進行繪制。但如果目前的視圖沒有子視圖, 那麼也就不需要進行繪制了。是以你會發現view中的dispatchdraw()方法又是一個空方法,而viewgroup的dispatchdraw()方法中就會有具體的繪制代碼。ondrawscrollbars 是對視圖的滾動條進行繪制。
  視窗的ui最終是需要通過surfaceflinger服務來統一渲染的, 而surfaceflinger服務在渲染視窗的ui之前, 需要計算基于各個視窗的z軸位置來計算它們的可見區域。而windowmanagerservice服務就是負責計算好每一個視窗的z軸位置之後, 還需要将它們設定到surfaceflinger服務中去, 以便surfaceflinger服務可以正确地渲染每一個視窗的ui。

statusbar

參考文獻:

http://blog.csdn.net/guolin_blog/article/details/16330267

http://www.cnblogs.com/franksunny/archive/2012/04/20/2459738.html

http://blog.csdn.net/qinjuning/article/details/8051811

http://blog.csdn.net/qinjuning/article/details/8074262

http://bbs.51cto.com/thread-1072344-1.html

該文章來自阿裡巴巴技術協會(ata)

作者:耕耘

繼續閱讀