Android的SurfaceView和TextureView介紹及使用示例
前言
一、什么是SurfaceView ?
SurfaceView 是一種用于直接將圖形繪制到屏幕的Android組件。與常規(guī)的 View 不同,SurfaceView 通過使用一個獨立的 Surface 來進行渲染,它不直接依賴于主 UI 線程,而是利用單獨的硬件加速的線程進行渲染。
1.1 SurfaceView 使用示例
SurfaceView 的常見用法通常是在視頻播放、相機預覽或?qū)崟r圖形渲染等場景中。以下是一個簡單的 SurfaceView 使用示例,它展示了如何在 Android 應(yīng)用中創(chuàng)建并使用 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.SurfaceView android: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; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surfaceView); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); // 注冊回調(diào) } @Override public void surfaceCreated(SurfaceHolder holder) { // 在 Surface 創(chuàng)建時調(diào)用,可以在此開始渲染 Surface surface = holder.getSurface(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 當 Surface 大小或格式改變時調(diào)用 // 更新渲染內(nèi)容或調(diào)整顯示內(nèi)容 } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 在 Surface 銷毀時調(diào)用 // 停止渲染操作并釋放資源 } }
在上述示例中,我們首先在布局中定義了一個 SurfaceView,然后通過 surfaceView.getHolder() 獲取 SurfaceHolder,并注冊了 SurfaceHolder.Callback 接口來處理 Surface 的生命周期。
1.2 SurfaceView 源碼概述
SurfaceView 主要用于處理需要高效、實時渲染的場景,例如視頻播放、游戲渲染、相機預覽等。它的渲染操作由后臺線程執(zhí)行,避免了與主 UI 線程的競爭,提升了性能。
主要類及源碼文件
SurfaceView 類位于 frameworks/base/core/java/android/view/SurfaceView.java。
通過 getHolder() 獲取與 SurfaceView 關(guān)聯(lián)的 SurfaceHolder。
SurfaceHolder 是一個接口,通過它可以獲取與 SurfaceView 關(guān)聯(lián)的 Surface 對象并進行渲染。
1.3 SurfaceView 的構(gòu)造與初始化
SurfaceView 在初始化時,首先通過 getHolder() 獲取 SurfaceHolder,然后注冊回調(diào)接口來處理 Surface 的生命周期。具體代碼如下:
public SurfaceView(Context context) { super(context); mSurfaceHolder = getHolder(); // 獲取 SurfaceHolder mSurfaceHolder.addCallback(this); // 注冊回調(diào) }
在此過程中,getHolder() 返回一個 SurfaceHolder 對象,該對象用于管理與 SurfaceView 關(guān)聯(lián)的 Surface。SurfaceHolder.Callback 回調(diào)接口的實現(xiàn)幫助我們在 Surface 創(chuàng)建、改變和銷毀時執(zhí)行相應(yīng)的操作。
1.4 SurfaceHolder.Callback 回調(diào)接口
SurfaceHolder.Callback 是一個關(guān)鍵接口,SurfaceView 使用它來處理與 Surface 相關(guān)的生命周期事件。它包括三個主要回調(diào)方法:
surfaceCreated(SurfaceHolder holder)
surfaceCreated() 方法在 Surface 被創(chuàng)建時調(diào)用。此時,SurfaceView 可以開始渲染圖形內(nèi)容。
@Override public void surfaceCreated(SurfaceHolder holder) { // 此時 Surface 創(chuàng)建成功,可以開始渲染 Surface surface = holder.getSurface(); // 進行圖形渲染,通常啟動渲染線程 }
surfaceChanged(SurfaceHolder holder, int format, int width, int height)
當 Surface 的格式或尺寸發(fā)生變化時,surfaceChanged() 會被調(diào)用。此時,應(yīng)用程序可以根據(jù)新的尺寸調(diào)整渲染內(nèi)容。
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 處理 Surface 格式或尺寸變化 }
surfaceDestroyed(SurfaceHolder holder)
當 Surface 被銷毀時,surfaceDestroyed() 會被調(diào)用。此時,應(yīng)用程序應(yīng)停止渲染操作并釋放資源。
@Override public void surfaceDestroyed(SurfaceHolder holder) { // 停止渲染線程并釋放資源 }
1.5 SurfaceView 渲染機制
SurfaceView 的渲染由后臺線程處理,渲染過程包括鎖定 Canvas、進行繪制并提交結(jié)果。
后臺線程與 Surface
SurfaceView 的渲染并不在主 UI 線程中進行,而是通過后臺線程來完成的。這是為了避免 UI 線程的阻塞,確保 UI 能夠流暢運行。
SurfaceView 在后臺線程中會使用 SurfaceHolder.lockCanvas() 獲取 Canvas 對象,然后進行圖形繪制。繪制完成后,通過 SurfaceHolder.unlockCanvasAndPost() 提交更新。
public void render(Surface surface) { Canvas canvas = null; try { canvas = holder.lockCanvas(null); // 鎖定 Canvas if (canvas != null) { // 在 Canvas 上繪制圖形內(nèi)容 canvas.drawColor(Color.BLACK); // 清屏 // 繪制其他內(nèi)容 } } finally { if (canvas != null) { holder.unlockCanvasAndPost(canvas); // 提交繪制結(jié)果 } } }
二、什么是TextureView?
TextureView 用于顯示一個內(nèi)容的紋理。它和 SurfaceView 的功能類似,但實現(xiàn)方式有所不同。
TextureView 允許將 OpenGL 渲染的內(nèi)容、視頻幀或其他圖像直接作用在 UI 線程上,并且能夠在任何地方進行動畫、旋轉(zhuǎn)或縮放,而不僅限于一個固定的 Surface。
相較于 SurfaceView,TextureView 在靈活性和控制方面有更多的優(yōu)勢。
2.1 TextureView 使用示例
下面是一個簡單的 TextureView 使用示例。
public class MyActivity extends AppCompatActivity { private TextureView textureView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textureView = findViewById(R.id.textureView); textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceCreated(SurfaceTexture surface, int width, int height) { // Surface 創(chuàng)建時,初始化 Surface Surface newSurface = new Surface(surface); // 可以在這里執(zhí)行渲染操作 } @Override public void onSurfaceChanged(SurfaceTexture surface, int width, int height) { // Surface 改變大小時 } @Override public void onSurfaceDestroyed(SurfaceTexture surface) { // Surface 銷毀時 } @Override public void onSurfaceUpdated(SurfaceTexture surface) { // 每次 Surface 更新時調(diào)用 } }); } }
2.2 TextureView 源碼概述
以下是 TextureView 源碼概述的核心內(nèi)容,詳細分析其結(jié)構(gòu)和工作原理。
1、關(guān)鍵類和接口
TextureView 類:TextureView 是整個視圖系統(tǒng)的核心,它繼承自 View 類。它的主要職責是通過 SurfaceTexture 渲染圖像內(nèi)容,并通過 Surface 顯示。
SurfaceTexture:SurfaceTexture 是與 OpenGL 渲染綁定的對象,用于顯示圖像流。它為 TextureView 提供了一個接口,通過它可以將渲染內(nèi)容傳輸?shù)?SurfaceView 或 TextureView。
Surface:Surface 是 Android 用于圖形渲染的基本容器。SurfaceTexture 通過 Surface 輸出圖形數(shù)據(jù),TextureView 通過此 Surface 顯示內(nèi)容。
SurfaceTextureListener 接口:該接口提供了與 SurfaceTexture 生命周期相關(guān)的回調(diào)方法,開發(fā)者可以通過實現(xiàn)該接口來響應(yīng) Surface 創(chuàng)建、更新和銷毀的事件。
2.3 TextureView 的構(gòu)造與初始化
1、構(gòu)造函數(shù)
TextureView 提供了多個構(gòu)造函數(shù),可以通過不同的方式初始化對象。最常見的構(gòu)造函數(shù)是:
public TextureView(Context context) { super(context); init(); }
在構(gòu)造函數(shù)中,TextureView 被初始化并配置了所需的 SurfaceTexture。通過調(diào)用 init() 方法,SurfaceTexture 和 Surface 將被創(chuàng)建,并為后續(xù)的圖像渲染做好準備。
private void init() { // 創(chuàng)建 SurfaceTexture 對象 mSurfaceTexture = new SurfaceTexture(false); // 創(chuàng)建 Surface 對象 mSurface = new Surface(mSurfaceTexture); // 設(shè)置視圖的緩沖區(qū)和其他默認參數(shù) setOpaque(true); // 設(shè)置是否為不透明 mSurfaceTextureListener = null; }
2. SurfaceTexture 和 Surface 的創(chuàng)建
TextureView 的核心是通過 SurfaceTexture 來獲取渲染的數(shù)據(jù)流,并通過 Surface 來顯示這些圖像內(nèi)容。創(chuàng)建 SurfaceTexture 和 Surface 的代碼如下:
mSurfaceTexture = new SurfaceTexture(false); // 創(chuàng)建 SurfaceTexture 實例 mSurface = new Surface(mSurfaceTexture); // 使用
SurfaceTexture 創(chuàng)建 Surface
SurfaceTexture 是渲染內(nèi)容的承載者,它接收渲染引擎(如 OpenGL)的輸出,并將其傳遞給 Surface。
Surface 是渲染結(jié)果的顯示容器,TextureView 通過該 Surface 來顯示圖像。
SurfaceTexture 的參數(shù) false 表示它是一個非透明的紋理。在大多數(shù)情況下,使用非透明紋理可以獲得更好的渲染性能。
2.4 SurfaceTextureListener 回調(diào)
TextureView 還提供了一個接口 SurfaceTextureListener,用于接收 SurfaceTexture 生命周期的回調(diào)事件。這個回調(diào)接口包含了多個方法,可以在 SurfaceTexture 創(chuàng)建、更新或銷毀時進行處理。
- onSurfaceCreated(SurfaceTexture surface, int width, int height):當 SurfaceTexture 創(chuàng)建時調(diào)用。此時可以開始渲染內(nèi)容。
- onSurfaceChanged(SurfaceTexture surface, int width, int height):當 SurfaceTexture 尺寸發(fā)生變化時調(diào)用??梢杂脕砀落秩緝?nèi)容或調(diào)整顯示尺寸。
- onSurfaceDestroyed(SurfaceTexture surface):當 SurfaceTexture 銷毀時調(diào)用,可以在此時釋放資源。
- onSurfaceUpdated(SurfaceTexture surface):每次 SurfaceTexture 更新時調(diào)用,用于通知渲染更新。
2.5 TextureView渲染流程
TextureView 的渲染流程主要依賴于 SurfaceTexture 和 Surface 來將圖像渲染到屏幕上。以下是該渲染流程的關(guān)鍵步驟:
初始化 SurfaceTexture 和 Surface:
TextureView 在初始化時創(chuàng)建一個 SurfaceTexture 對象,該對象用于接收圖形數(shù)據(jù)。
然后將 SurfaceTexture 封裝為 Surface,Surface 用于顯示圖像內(nèi)容。
圖像數(shù)據(jù)傳遞到 SurfaceTexture:
圖形引擎(如 OpenGL)將渲染結(jié)果傳遞給 SurfaceTexture,這些數(shù)據(jù)會被存儲在 SurfaceTexture 中。
3.SurfaceTexture 更新:
一旦 SurfaceTexture 中的圖像數(shù)據(jù)更新,TextureView 會收到通知,并準備將新圖像內(nèi)容顯示出來。
SurfaceTexture 會將最新的圖像數(shù)據(jù)傳遞給關(guān)聯(lián)的 Surface。
顯示圖像內(nèi)容:
Surface 在 TextureView 上渲染和顯示圖像內(nèi)容。此時,TextureView 會將圖像數(shù)據(jù)呈現(xiàn)到屏幕上。
三、SurfaceView和TextureView區(qū)別
特性 | SurfaceView | TextureView |
---|---|---|
渲染方式 | 渲染內(nèi)容直接通過硬件層輸出,不經(jīng)過 UI 層,繞過屏幕緩沖區(qū) | 通過 SurfaceTexture 渲染內(nèi)容,經(jīng)過 UI 層(即視圖層)顯示 |
性能 | 高性能,適合要求低延遲、高幀率的應(yīng)用,如視頻播放、實時游戲等 | 性能相對較低,適用于對 UI 層交互、動畫有要求的應(yīng)用 |
渲染效率 | 渲染在獨立的硬件層,減少 UI 線程負擔,圖形處理獨立 | 渲染經(jīng)過 UI 層,渲染性能相對較低,可能會受到 UI 層操作影響 |
硬件加速支持 | 直接使用硬件加速,不依賴 UI 線程,適合高效圖形渲染 | 使用硬件加速,但圖形渲染受 UI 線程限制 |
變換與動畫支持 | 不支持內(nèi)建的圖像變換,若需動畫或變換需要依賴外部圖形庫如 OpenGL | 支持矩陣變換(旋轉(zhuǎn)、縮放、平移等),支持視圖動畫和動態(tài)效果 |
視圖層級與嵌套 | 渲染層與 UI 層分離,不能與其他視圖進行直接交互或嵌套 | 渲染內(nèi)容在 UI 層,可以和其他視圖層級交互、嵌套和變換 |
生命周期管理 | 通過 SurfaceHolder.Callback 回調(diào)接口管理 Surface 的生命周期 | 通過 SurfaceTextureListener 回調(diào)接口管理 SurfaceTexture 生命周期 |
適用場景 | 適用于視頻播放、實時游戲渲染等對性能要求高的應(yīng)用 | 適用于動態(tài)變換、動畫和需要與 UI 層交互的場景(如視頻展示、圖像旋轉(zhuǎn)) |
支持的 UI 操作 | 不支持直接與 UI 層進行交互(例如點擊、動畫、視圖更新等) | 支持與 UI 層的交互,支持視圖動畫(例如 setTransform() 變換) |
硬件渲染與UI渲染 | 渲染直接在硬件層進行,不依賴 UI 線程 | 渲染通過 UI 層進行,UI 線程參與渲染處理,可能有性能開銷 |
透明背景支持 | 不直接支持透明背景 | 支持透明背景,適合需要透明或部分透明效果的應(yīng)用 |
支持多層顯示 | 支持多層顯示,但通常是通過 Surface 進行不同圖層顯示 | 支持多圖層顯示,允許將多個 TextureView 嵌套并渲染不同內(nèi)容 |
顯示內(nèi)容更新 | 渲染內(nèi)容更新較為簡單,依賴 lockCanvas、unlockCanvasAndPost | 顯示內(nèi)容更新通過 SurfaceTexture 更新,內(nèi)容刷新通過 updateTexImage() |
硬件解碼視頻 | 非常適合硬件解碼視頻,視頻數(shù)據(jù)直接渲染到硬件層 | 不如 SurfaceView 高效,視頻數(shù)據(jù)需要通過 SurfaceTexture 渲染 |
UI 線程影響 | 不會受到 UI 線程影響,獨立的渲染線程 | 渲染依賴 UI 線程,可能會影響 UI 線程的流暢性,特別是在高負荷情況下 |
可嵌入到布局中 | 不可以直接與其他視圖一起進行布局 | 可以像普通視圖一樣嵌入布局,支持與其他視圖交互和變換 |
旋轉(zhuǎn)與縮放 | 不支持內(nèi)建旋轉(zhuǎn)、縮放等變換,需使用外部圖形庫 | 支持內(nèi)建旋轉(zhuǎn)、縮放和其他變換,支持多種變換方式 |
API 支持 | 支持大部分 Android 設(shè)備,并且對硬件解碼支持較好 | 支持大部分 Android 設(shè)備,適合需要在視圖層做渲染處理的場景 |
渲染線程 | 在獨立線程中進行渲染,UI 線程與渲染分離 | 渲染在 UI 線程中進行,UI 操作與渲染共用一個線程 |
到此這篇關(guān)于Android的SurfaceView和TextureView介紹的文章就介紹到這了,更多相關(guān)Android SurfaceView和TextureView內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中okhttp3.4.1+retrofit2.1.0實現(xiàn)離線緩存
這篇文章主要介紹了Android中okhttp3.4.1結(jié)合retrofit2.1.0實現(xiàn)離線緩存,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10android studio使用SQLiteOpenHelper()建立數(shù)據(jù)庫的方法
這篇文章主要介紹了android studio使用SQLiteOpenHelper()建立數(shù)據(jù)庫的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03Android關(guān)于BottomNavigationView使用指南
本文主要介紹了Android關(guān)于BottomNavigationView使用指南,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01Android中獲得正在運行的程序和系統(tǒng)服務(wù)的方法
這篇文章主要介紹了Android中獲得正在運行的程序和系統(tǒng)服務(wù)的方法,分別是對ActivityManager.RunningAppProcessInfo類和ActivityManager.RunningServiceInfo類的使用,需要的朋友可以參考下2016-02-02Android Studio中導入module的方法(簡單版)
這篇文章主要介紹了AndroidStudio中導入module的方法,本文是一篇簡易版的教程,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-01-01