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