文章目錄
- 前言
- 一、什么是SurfaceView ?
- 1.1 SurfaceView 使用示例
- 1.2 SurfaceView 源碼概述
- 1.3 SurfaceView 的構造與初始化
- 1.4 SurfaceHolder.Callback 回調接口
- 1.5 SurfaceView 渲染機制
- 二、什么是TextureView?
- 2.1 TextureView 使用示例
- 2.2 TextureView 源碼概述
- 2.3 TextureView 的構造與初始化
- 2.4 SurfaceTextureListener 回調
- 2.5 TextureView渲染流程
- 三、SurfaceView和TextureView區別
前言
一、什么是SurfaceView ?
SurfaceView 是一種用于直接將圖形繪制到屏幕的Android組件。與常規的 View 不同,SurfaceView 通過使用一個獨立的 Surface 來進行渲染,它不直接依賴于主 UI 線程,而是利用單獨的硬件加速的線程進行渲染。
1.1 SurfaceView 使用示例
SurfaceView 的常見用法通常是在視頻播放、相機預覽或實時圖形渲染等場景中。以下是一個簡單的 SurfaceView 使用示例,它展示了如何在 Android 應用中創建并使用 SurfaceView:
布局 XML 文件 (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><android.view.SurfaceViewandroid:id="@+id/surfaceView"android:layout_width="match_parent"android:layout_height="match_parent" />
</LinearLayout>
import android.os.Bundle;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {private SurfaceView surfaceView;private SurfaceHolder surfaceHolder;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);surfaceView = findViewById(R.id.surfaceView);surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(this); // 注冊回調}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// 在 Surface 創建時調用,可以在此開始渲染Surface surface = holder.getSurface();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {// 當 Surface 大小或格式改變時調用// 更新渲染內容或調整顯示內容}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// 在 Surface 銷毀時調用// 停止渲染操作并釋放資源}
}
在上述示例中,我們首先在布局中定義了一個 SurfaceView,然后通過 surfaceView.getHolder() 獲取 SurfaceHolder,并注冊了 SurfaceHolder.Callback 接口來處理 Surface 的生命周期。
1.2 SurfaceView 源碼概述
SurfaceView 主要用于處理需要高效、實時渲染的場景,例如視頻播放、游戲渲染、相機預覽等。它的渲染操作由后臺線程執行,避免了與主 UI 線程的競爭,提升了性能。
主要類及源碼文件
SurfaceView 類位于 frameworks/base/core/java/android/view/SurfaceView.java。
通過 getHolder() 獲取與 SurfaceView 關聯的 SurfaceHolder。
SurfaceHolder 是一個接口,通過它可以獲取與 SurfaceView 關聯的 Surface 對象并進行渲染。
1.3 SurfaceView 的構造與初始化
SurfaceView 在初始化時,首先通過 getHolder() 獲取 SurfaceHolder,然后注冊回調接口來處理 Surface 的生命周期。具體代碼如下:
public SurfaceView(Context context) {super(context);mSurfaceHolder = getHolder(); // 獲取 SurfaceHoldermSurfaceHolder.addCallback(this); // 注冊回調
}
在此過程中,getHolder() 返回一個 SurfaceHolder 對象,該對象用于管理與 SurfaceView 關聯的 Surface。SurfaceHolder.Callback 回調接口的實現幫助我們在 Surface 創建、改變和銷毀時執行相應的操作。
1.4 SurfaceHolder.Callback 回調接口
SurfaceHolder.Callback 是一個關鍵接口,SurfaceView 使用它來處理與 Surface 相關的生命周期事件。它包括三個主要回調方法:
- surfaceCreated(SurfaceHolder holder)
surfaceCreated() 方法在 Surface 被創建時調用。此時,SurfaceView 可以開始渲染圖形內容。
@Override
public void surfaceCreated(SurfaceHolder holder) {// 此時 Surface 創建成功,可以開始渲染Surface surface = holder.getSurface();// 進行圖形渲染,通常啟動渲染線程
}
- surfaceChanged(SurfaceHolder holder, int format, int width, int height)
當 Surface 的格式或尺寸發生變化時,surfaceChanged() 會被調用。此時,應用程序可以根據新的尺寸調整渲染內容。
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {// 處理 Surface 格式或尺寸變化
}
- surfaceDestroyed(SurfaceHolder holder)
當 Surface 被銷毀時,surfaceDestroyed() 會被調用。此時,應用程序應停止渲染操作并釋放資源。
@Override
public void surfaceDestroyed(SurfaceHolder holder) {// 停止渲染線程并釋放資源
}
1.5 SurfaceView 渲染機制
SurfaceView 的渲染由后臺線程處理,渲染過程包括鎖定 Canvas、進行繪制并提交結果。
后臺線程與 Surface
SurfaceView 的渲染并不在主 UI 線程中進行,而是通過后臺線程來完成的。這是為了避免 UI 線程的阻塞,確保 UI 能夠流暢運行。
SurfaceView 在后臺線程中會使用 SurfaceHolder.lockCanvas() 獲取 Canvas 對象,然后進行圖形繪制。繪制完成后,通過 SurfaceHolder.unlockCanvasAndPost() 提交更新。
public void render(Surface surface) {Canvas canvas = null;try {canvas = holder.lockCanvas(null); // 鎖定 Canvasif (canvas != null) {// 在 Canvas 上繪制圖形內容canvas.drawColor(Color.BLACK); // 清屏// 繪制其他內容}} finally {if (canvas != null) {holder.unlockCanvasAndPost(canvas); // 提交繪制結果}}
}
二、什么是TextureView?
TextureView 用于顯示一個內容的紋理。它和 SurfaceView 的功能類似,但實現方式有所不同。
TextureView 允許將 OpenGL 渲染的內容、視頻幀或其他圖像直接作用在 UI 線程上,并且能夠在任何地方進行動畫、旋轉或縮放,而不僅限于一個固定的 Surface。
相較于 SurfaceView,TextureView 在靈活性和控制方面有更多的優勢。
2.1 TextureView 使用示例
下面是一個簡單的 TextureView 使用示例。
public class MyActivity extends AppCompatActivity {private TextureView textureView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textureView = findViewById(R.id.textureView);textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceCreated(SurfaceTexture surface, int width, int height) {// Surface 創建時,初始化 SurfaceSurface newSurface = new Surface(surface);// 可以在這里執行渲染操作}@Overridepublic void onSurfaceChanged(SurfaceTexture surface, int width, int height) {// Surface 改變大小時}@Overridepublic void onSurfaceDestroyed(SurfaceTexture surface) {// Surface 銷毀時}@Overridepublic void onSurfaceUpdated(SurfaceTexture surface) {// 每次 Surface 更新時調用}});}
}
2.2 TextureView 源碼概述
以下是 TextureView 源碼概述的核心內容,詳細分析其結構和工作原理。
1、關鍵類和接口
TextureView 類:TextureView 是整個視圖系統的核心,它繼承自 View 類。它的主要職責是通過 SurfaceTexture 渲染圖像內容,并通過 Surface 顯示。
SurfaceTexture:SurfaceTexture 是與 OpenGL 渲染綁定的對象,用于顯示圖像流。它為 TextureView 提供了一個接口,通過它可以將渲染內容傳輸到 SurfaceView 或 TextureView。
Surface:Surface 是 Android 用于圖形渲染的基本容器。SurfaceTexture 通過 Surface 輸出圖形數據,TextureView 通過此 Surface 顯示內容。
SurfaceTextureListener 接口:該接口提供了與 SurfaceTexture 生命周期相關的回調方法,開發者可以通過實現該接口來響應 Surface 創建、更新和銷毀的事件。
2.3 TextureView 的構造與初始化
1、構造函數
TextureView 提供了多個構造函數,可以通過不同的方式初始化對象。最常見的構造函數是:
public TextureView(Context context) {super(context);init();
}
在構造函數中,TextureView 被初始化并配置了所需的 SurfaceTexture。通過調用 init() 方法,SurfaceTexture 和 Surface 將被創建,并為后續的圖像渲染做好準備。
private void init() {// 創建 SurfaceTexture 對象mSurfaceTexture = new SurfaceTexture(false);// 創建 Surface 對象mSurface = new Surface(mSurfaceTexture);// 設置視圖的緩沖區和其他默認參數setOpaque(true); // 設置是否為不透明mSurfaceTextureListener = null;
}
2. SurfaceTexture 和 Surface 的創建
TextureView 的核心是通過 SurfaceTexture 來獲取渲染的數據流,并通過 Surface 來顯示這些圖像內容。創建 SurfaceTexture 和 Surface 的代碼如下:
mSurfaceTexture = new SurfaceTexture(false); // 創建 SurfaceTexture 實例
mSurface = new Surface(mSurfaceTexture); // 使用
SurfaceTexture 創建 Surface
SurfaceTexture 是渲染內容的承載者,它接收渲染引擎(如 OpenGL)的輸出,并將其傳遞給 Surface。
Surface 是渲染結果的顯示容器,TextureView 通過該 Surface 來顯示圖像。
SurfaceTexture 的參數 false 表示它是一個非透明的紋理。在大多數情況下,使用非透明紋理可以獲得更好的渲染性能。
2.4 SurfaceTextureListener 回調
TextureView 還提供了一個接口 SurfaceTextureListener,用于接收 SurfaceTexture 生命周期的回調事件。這個回調接口包含了多個方法,可以在 SurfaceTexture 創建、更新或銷毀時進行處理。
- onSurfaceCreated(SurfaceTexture surface, int width, int height):當 SurfaceTexture 創建時調用。此時可以開始渲染內容。
- onSurfaceChanged(SurfaceTexture surface, int width, int height):當 SurfaceTexture 尺寸發生變化時調用。可以用來更新渲染內容或調整顯示尺寸。
- onSurfaceDestroyed(SurfaceTexture surface):當 SurfaceTexture 銷毀時調用,可以在此時釋放資源。
- onSurfaceUpdated(SurfaceTexture surface):每次 SurfaceTexture 更新時調用,用于通知渲染更新。
2.5 TextureView渲染流程
TextureView 的渲染流程主要依賴于 SurfaceTexture 和 Surface 來將圖像渲染到屏幕上。以下是該渲染流程的關鍵步驟:
- 初始化 SurfaceTexture 和 Surface:
TextureView 在初始化時創建一個 SurfaceTexture 對象,該對象用于接收圖形數據。
然后將 SurfaceTexture 封裝為 Surface,Surface 用于顯示圖像內容。
- 圖像數據傳遞到 SurfaceTexture:
圖形引擎(如 OpenGL)將渲染結果傳遞給 SurfaceTexture,這些數據會被存儲在 SurfaceTexture 中。
3.SurfaceTexture 更新:
一旦 SurfaceTexture 中的圖像數據更新,TextureView 會收到通知,并準備將新圖像內容顯示出來。
SurfaceTexture 會將最新的圖像數據傳遞給關聯的 Surface。
- 顯示圖像內容:
Surface 在 TextureView 上渲染和顯示圖像內容。此時,TextureView 會將圖像數據呈現到屏幕上。
三、SurfaceView和TextureView區別
特性 | SurfaceView | TextureView |
---|---|---|
渲染方式 | 渲染內容直接通過硬件層輸出,不經過 UI 層,繞過屏幕緩沖區 | 通過 SurfaceTexture 渲染內容,經過 UI 層(即視圖層)顯示 |
性能 | 高性能,適合要求低延遲、高幀率的應用,如視頻播放、實時游戲等 | 性能相對較低,適用于對 UI 層交互、動畫有要求的應用 |
渲染效率 | 渲染在獨立的硬件層,減少 UI 線程負擔,圖形處理獨立 | 渲染經過 UI 層,渲染性能相對較低,可能會受到 UI 層操作影響 |
硬件加速支持 | 直接使用硬件加速,不依賴 UI 線程,適合高效圖形渲染 | 使用硬件加速,但圖形渲染受 UI 線程限制 |
變換與動畫支持 | 不支持內建的圖像變換,若需動畫或變換需要依賴外部圖形庫如 OpenGL | 支持矩陣變換(旋轉、縮放、平移等),支持視圖動畫和動態效果 |
視圖層級與嵌套 | 渲染層與 UI 層分離,不能與其他視圖進行直接交互或嵌套 | 渲染內容在 UI 層,可以和其他視圖層級交互、嵌套和變換 |
生命周期管理 | 通過 SurfaceHolder.Callback 回調接口管理 Surface 的生命周期 | 通過 SurfaceTextureListener 回調接口管理 SurfaceTexture 生命周期 |
適用場景 | 適用于視頻播放、實時游戲渲染等對性能要求高的應用 | 適用于動態變換、動畫和需要與 UI 層交互的場景(如視頻展示、圖像旋轉) |
支持的 UI 操作 | 不支持直接與 UI 層進行交互(例如點擊、動畫、視圖更新等) | 支持與 UI 層的交互,支持視圖動畫(例如 setTransform() 變換) |
硬件渲染與UI渲染 | 渲染直接在硬件層進行,不依賴 UI 線程 | 渲染通過 UI 層進行,UI 線程參與渲染處理,可能有性能開銷 |
透明背景支持 | 不直接支持透明背景 | 支持透明背景,適合需要透明或部分透明效果的應用 |
支持多層顯示 | 支持多層顯示,但通常是通過 Surface 進行不同圖層顯示 | 支持多圖層顯示,允許將多個 TextureView 嵌套并渲染不同內容 |
顯示內容更新 | 渲染內容更新較為簡單,依賴 lockCanvas、unlockCanvasAndPost | 顯示內容更新通過 SurfaceTexture 更新,內容刷新通過 updateTexImage() |
硬件解碼視頻 | 非常適合硬件解碼視頻,視頻數據直接渲染到硬件層 | 不如 SurfaceView 高效,視頻數據需要通過 SurfaceTexture 渲染 |
UI 線程影響 | 不會受到 UI 線程影響,獨立的渲染線程 | 渲染依賴 UI 線程,可能會影響 UI 線程的流暢性,特別是在高負荷情況下 |
可嵌入到布局中 | 不可以直接與其他視圖一起進行布局 | 可以像普通視圖一樣嵌入布局,支持與其他視圖交互和變換 |
旋轉與縮放 | 不支持內建旋轉、縮放等變換,需使用外部圖形庫 | 支持內建旋轉、縮放和其他變換,支持多種變換方式 |
API 支持 | 支持大部分 Android 設備,并且對硬件解碼支持較好 | 支持大部分 Android 設備,適合需要在視圖層做渲染處理的場景 |
渲染線程 | 在獨立線程中進行渲染,UI 線程與渲染分離 | 渲染在 UI 線程中進行,UI 操作與渲染共用一個線程 |