文章目錄
- Window繪制流程
- Window Manager Service(WMS)
- Surface
- SurfaceFlinger
- 安卓View層次結構
- Activity
- PhoneWindow
- Activity與PhoneWindow兩者之間的關系
- ViewRootImpl
- DecorView
- DecorView 的作用
- DecorView 的結構
- 總結
- Activity創建流程
- View invalidate調用流程
Window繪制流程
在安卓系統中,Window Manager Service(WMS)和 Surface 是與窗口管理和圖形顯示相關的重要概念。
Window Manager Service(WMS)
- 功能概述:WMS 是安卓系統中負責管理窗口的系統服務。它主要負責窗口的創建、銷毀、布局、顯示順序以及與用戶交互等方面的管理。
- 工作原理:當一個應用程序創建一個窗口(例如 Activity 的界面)時,它會向 WMS 發送請求。WMS 會為該窗口分配一個唯一的標識,并根據窗口的屬性(如大小、位置、層級等)將其添加到窗口管理列表中。在繪制窗口時,WMS 會協調各個窗口的位置和顯示順序,確保它們按照正確的方式顯示在屏幕上。當用戶進行觸摸屏幕等交互操作時,WMS 會根據觸摸事件的位置和窗口的布局,將事件分發給相應的窗口進行處理。
Surface
- 概念:Surface 是安卓圖形系統中的一個重要概念,它代表了一個可繪制的區域,用于在屏幕上顯示圖形內容。可以將 Surface 看作是一塊畫布,應用程序可以在上面繪制各種圖形、圖像和文本等內容。
- 作用:每個窗口都有一個或多個 Surface 與之關聯。當應用程序需要繪制窗口的內容時,它會通過 Surface 來獲取繪圖的上下文,然后使用圖形庫(如 OpenGL)在 Surface 上進行繪制。繪制完成后,Surface 會將繪制的結果提交給系統的圖形合成器(通常是 Surface Flinger),由圖形合成器將各個窗口的 Surface 進行合成,最終顯示在屏幕上。
- 與 WMS 的關系:WMS 負責管理窗口的整體布局和顯示順序,而 Surface 則是窗口內容繪制的載體。WMS 會根據窗口的狀態和用戶的操作,通知應用程序更新其 Surface 的內容。例如,當窗口大小發生變化時,WMS 會通知應用程序重新繪制 Surface 以適應新的大小。同時,WMS 也會與 Surface Flinger 協作,確保各個 Surface 能夠按照正確的順序和方式進行合成和顯示。
SurfaceFlinger
SurfaceFlinger是 Android 系統中的一個關鍵服務,主要負責將不同應用程序的 2D、3D surface 進行組合,并將最終合成的圖像發送到顯示設備進行顯示。
安卓View層次結構
Activity包含PhoneWindow、DecorView、ViewRootImpl等
Activity
Activity屬于安卓應用程序的四大組件之一,它為用戶提供了一個可視化的界面,讓用戶能夠與應用進行交互。每一個Activity都代表著一個屏幕畫面,像是登錄界面、主界面等。
在安卓中,Activity是由ActivityManagerService(AMS,活動管理器服務) 創建的 。
以下是Activity的一個簡單示例:
import android.app.Activity;
import android.os.Bundle;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}
PhoneWindow
PhoneWindow是Window類的具體實現,Window類在安卓系統里代表著一個頂級的視覺容器,它負責管理窗口的樣式、背景以及標題欄等。PhoneWindow主要處理窗口的具體顯示邏輯,例如設置窗口的背景、標題欄、內容視圖等。
Activity與PhoneWindow兩者之間的關系
- 包含關系:Activity包含一個PhoneWindow對象,在Activity的創建過程中,會默認創建一個PhoneWindow對象。
- 視圖關聯:Activity通過PhoneWindow來設置和管理其視圖。Activity的setContentView()方法實際上是調用了PhoneWindow的setContentView()方法。
// Activity類中的setContentView方法
@Override
public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();
}
Activity是用戶交互的界面載體,負責處理用戶的操作和業務邏輯;PhoneWindow則是窗口的具體實現,負責窗口的顯示和管理。它們緊密協作,共同構成了安卓應用程序的用戶界面。
ViewRootImpl
- 概述:ViewRootImpl是View與WindowManager之間的橋梁,它不是一個真正的View,但它管理著一個View樹的根節點,在Android系統中,每個Window都對應著一個ViewRootImpl實例。
作用 - 視圖繪制管理:負責協調View樹的繪制過程,包括測量(measure)、布局(layout)和繪制(draw)三個階段。它會根據屏幕的刷新頻率,通過Choreographer來觸發視圖的重繪,確保界面能夠及時更新。
- 事件分發:接收系統傳遞的輸入事件,如觸摸事件、按鍵事件等,并將這些事件分發給View樹中的各個View進行處理。它是事件從系統到應用View的重要傳遞環節。
- 與窗口管理器交互:與WindowManagerService(WMS)進行通信,負責處理窗口的創建、銷毀、大小調整等操作。例如,當Activity啟動時,ViewRootImpl會與WMS交互來創建窗口,并將DecorView添加到窗口中。
DecorView
在 Android 系統中,DecorView 是窗口(Window)的最頂層視圖(頂級 ViewGroup),它作為整個窗口的根視圖,包含了系統的裝飾(如狀態欄、導航欄)和應用程序的內容視圖(如 Activity 的布局)。
DecorView 的作用
- 窗口的根容器:每個 Activity 的窗口(PhoneWindow)都包含一個 DecorView,它是 View 層級的最頂層。
- 管理系統 UI:DecorView 負責處理系統窗口裝飾(如狀態欄、ActionBar/Toolbar)和應用程序內容的協調。
- 內容視圖的父容器:開發者通過 setContentView() 設置的布局會被添加到 DecorView 的一個子 ViewGroup(通常是 FrameLayout,ID 為 android.R.id.content)中。
DecorView 的結構
DecorView是每個Activity界面的頂層視圖,它是一個FrameLayout。
DecorView 通常包含以下兩部分:
- 系統裝飾部分
狀態欄(Status Bar)、導航欄(Navigation Bar)等系統 UI。
由主題(Theme)控制是否顯示(如全屏模式會隱藏系統裝飾)。 - 應用內容部分
通過 setContentView() 設置的布局會被添加到 android.R.id.content 這個子 FrameLayout 中。
總結
DecorView 是 Android 窗口系統的核心組件,作為連接系統 UI 和應用內容的橋梁。理解它的結構和功能有助于處理全屏、鍵盤交互、窗口屬性等高級場景。實際開發中,通常只需通過 setContentView() 操作內容部分,而無需直接操作 DecorView。
Activity創建流程
Activity中AMS創建的。
- window的初始化是在 Acticity 創建的時候初始化, 在Acticity對象創建后,會調用attach方法,Windows對象就是這個時候創建的。
- Activity的setContentView其實調用的是PhoneWindow的setContentView。
- setContentView中調用installDecor()進行DecorView的初始化。
- onResume中會調用WindowMangerImpl的addView, ViewRootImpl就是在這個addView中創建的。
- addView會調用ViewRootImpl的setView,setView調用WMS的addView并調用requestLayout。
- requestLayout調用scheduleTraversals(會創建surface),scheduleTraversals調用見下段invalidate流程后段會有講到主要是調用measure,layout,draw。
如下圖為addView流程
View invalidate調用流程
- 起始調用
當我們希望重繪某個View時,直接調用其invalidate方法 。比如在自定義View的事件處理方法(如onClick) 或者數據更新邏輯中調用。invalidate方法會轉而調用invalidate(true) ,這里的參數表示是否同時使繪圖緩存無效,一般全量刷新時為true。 - invalidateInternal方法
invalidate(true)會調用invalidateInternal方法,此方法會進行以下操作:
判斷是否需要重繪:調用skipInvalidate方法判斷該View是否不需要重繪,不需要重繪的條件是該View不可見并且未進行動畫。
- 處理重繪標志位:進一步判斷View是否需要繪制,如判斷表達式(mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ,若滿足重繪條件,則處理相關標志位,將當前View標記為 “臟” ,即設置mPrivateFlags中的相關標志,表明該View需要重繪。
- 確定重繪區域:對于開啟硬件加速的應用程序,調用父視圖的invalidateChild函數繪制整個區域;否則只繪制指定的dirty區域(r變量所指區域)。這是一個向上回溯的過程,每一層的父View都將自己的顯示區域與傳入的刷新Rect做交集。
- ViewGroup中的調用
- invalidateChild方法:在ViewGroup中,invalidateChild方法會從當前的布局View向上不斷遍歷其父布局。它會先處理子View重繪相關邏輯,比如根據子View情況設置一些標志位,然后調用父布局的invalidateChildInParent方法。
- invalidateChildInParent方法:該方法會計算需要重繪的區域 ,涉及到location數組(表示自身左邊、上邊距離父組件的距離,確立在坐標系的相對位置 )和dirty矩形(包含自身寬高,確立需要重繪的面積大小 )。計算后會繼續向上請求父布局重繪,直到父布局為ViewRootImpl 。
- ViewRootImpl中的處理
- invalidateChildInParent方法:ViewRootImpl中的invalidateChildInParent方法會檢查線程是否正確 ,若dirty為null,表示要重繪整個區域,直接調用invalidate;若dirty為空且沒有動畫,就不需要重繪,直接返回。否則會對重繪區域進行進一步處理,如根據滾動偏移等情況調整區域。
- invalidate方法:調用invalidate方法后,會通過scheduleTraversals方法安排一次視圖遍歷。
- 視圖遍歷與繪制
- scheduleTraversals方法:安排視圖遍歷工作,將任務添加到消息隊列,待合適時機(比如下一次繪制周期 )執行。
- performTraversals方法:視圖遍歷的核心方法,依次執行測量(performMeasure ,調用measure ,最終到onMeasure )、布局(performLayout ,調用layout ,最終到onLayout )、繪制(performDraw ,調用draw ,最終到onDraw )等步驟 ,完成整個View樹的更新繪制 。其中performDraw會進一步調用drawSoftware ,最終觸發View的draw方法,開始實際繪制。
Android Framework學習一:系統框架、啟動過程
Android Framework學習二:Activity創建及View繪制流程
作者:帥得不敢出門