Android 應用程式架構 UI 是以以 View 為開頭的物件階層為基礎。所有 UI 元素都會經過一系列的測量和版面配置程序,以便將這些元素套用至矩形區域。接著,所有可見的 View 物件都會算繪至應用程式移至前景時由 WindowManager 設定的表面。應用程式的 UI 執行緒會執行版面配置,並將每個影格轉譯至緩衝區。
SurfaceView
SurfaceView 是一種元件,可用於在檢視區塊階層中嵌入額外的複合層。SurfaceView 會採用與其他檢視畫面相同的版面配置參數,因此可像其他檢視畫面一樣進行操作,但 SurfaceView 的內容是透明的。
使用外部緩衝區來源 (例如 GL 內容或媒體解碼器) 進行算繪時,您需要從緩衝區來源複製緩衝區,才能在畫面上顯示緩衝區。您可以使用 SurfaceView 執行這項操作。
當 SurfaceView 的 View 元件即將顯示時,架構會要求 SurfaceControl 向 SurfaceFlinger 要求新的介面。如要在建立或銷毀表面時接收回呼,請使用 SurfaceHolder 介面。根據預設,新建的介面會置於應用程式 UI 介面後方。您可以覆寫預設的 Z 排序,將新途徑置於頂端。
在需要將轉譯結果轉譯至個別介面 (例如使用 Camera API 或 OpenGL ES 情境轉譯) 的情況下,使用 SurfaceView 轉譯會更有幫助。使用 SurfaceView 轉譯時,SurfaceFlinger 會直接將緩衝區組合至螢幕。如果沒有 SurfaceView,您就需要將緩衝區合成至螢幕外介面,然後再合成至螢幕,因此使用 SurfaceView 算繪可省去額外的工作。使用 SurfaceView 算繪後,請使用 UI 執行緒與活動生命週期協調,並視需要調整檢視畫面的大小或位置。接著,硬體編譯器會將應用程式 UI 與其他圖層混合。
新的介面是 BufferQueue 的生產者端,其消費者是 SurfaceFlinger 層。您可以使用任何可饋送 BufferQueue 的機制更新途徑,例如途徑提供的 Canvas 函式、附加 EGLSurface 並使用 GLES 在途徑上繪圖,或是設定媒體解碼器以寫入途徑。
SurfaceView 和活動生命週期
使用 SurfaceView 時,請從主 UI 執行緒以外的執行緒轉譯表面。
對於含有 SurfaceView 的活動,有兩個獨立但相互依賴的狀態機器:
- 應用程式
onCreate
/onResume
/onPause
- 建立/變更/銷毀介面
活動啟動時,您會依序收到回呼:
onCreate()
onResume()
surfaceCreated()
surfaceChanged()
點選「返回」後,您會看到:
onPause()
surfaceDestroyed()
(在表面消失前呼叫)
如果您旋轉螢幕,系統會解構並重新建立活動,讓您看到完整的週期。您可以查看 isFinishing()
來判斷是否為快速重新啟動。您可以快速啟動/停止活動,讓 surfaceCreated()
在 onPause()
之後發生。
如果輕觸電源鍵讓螢幕變黑,您只會看到 onPause()
,而不會看到 surfaceDestroyed()
。途徑會保持啟用狀態,且轉譯作業可以繼續進行。如果您持續要求,可以繼續收到編排器事件。如果您有鎖定螢幕,且強制使用不同的方向,則在裝置解除空白時,可能會重新啟動活動。否則,您可以使用與先前相同的介面,讓螢幕停止空白。
執行緒的生命週期可以與介面或活動繫結,這取決於您希望在螢幕空白時發生的情況。執行緒可以在活動開始/停止或表面建立/銷毀時啟動/停止。
在活動開始/停止時啟動/停止執行緒,可與應用程式生命週期搭配使用。您會在 onResume()
中啟動轉譯器執行緒,並在 onStop()
中停止。建立及設定執行緒時,有時會發現表面已存在,有時則不會 (例如,使用電源鍵切換螢幕後,它仍處於活動狀態)。您必須等待表面建立完成,才能在執行緒中進行初始化。您無法在 surfaceCreate()
回呼中進行初始化,因為如果未重新建立途徑,系統就不會再次觸發。請改為查詢或快取途徑狀態,然後將其轉送至轉譯器執行緒。
在途徑建立/銷毀時啟動/停止執行緒,可確保途徑和轉譯器在邏輯上相互交織。您可以在建立途徑後啟動執行緒,這樣就能避免一些執行緒間通訊問題;而建立/變更途徑的訊息會直接轉寄。為確保在螢幕空白時停止轉譯,並在螢幕顯示內容時恢復轉譯,請告知 Choreographer 停止叫用影格繪製回呼。如果轉譯器執行緒正在執行,onResume()
會繼續執行回呼。不過,如果您根據影格之間的經過時間製作動畫,下一個事件到達前可能會有很大的間隔;使用明確的暫停/繼續訊息可解決這個問題。
無論執行緒的生命週期是否與活動或途徑相關,這兩個選項都會著重於如何設定轉譯器執行緒,以及是否正在執行。相關問題是從活動終止 (在 onStop()
或 onSaveInstanceState()
中) 時從執行緒中擷取狀態;在這種情況下,將執行緒的生命週期與活動綁定最為合適,因為在加入轉譯器執行緒後,您可以不透過同步化原語法存取轉譯的執行緒狀態。
GLSurfaceView
GLSurfaceView 類別提供輔助類別,用於管理 EGL 情境、執行緒間通訊,以及與活動生命週期互動。您不必使用 GLSurfaceView 就能使用 GLES。
舉例來說,GLSurfaceView 會建立算繪執行緒,並在該執行緒中設定 EGL 情境。活動暫停時,系統會自動清除狀態。大多數應用程式不需要瞭解 EGL 相關資訊,即可搭配 GLSurfaceView 使用 GLES。
在大多數情況下,GLSurfaceView 可讓您更輕鬆地使用 GLES。在某些情況下,這可能會造成干擾。