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í)圖形渲染等場(chǎng)景中。以下是一個(gè)簡(jiǎn)單的 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); // 注冊(cè)回調(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,并注冊(cè)了 SurfaceHolder.Callback 接口來處理 Surface 的生命周期。
1.2 SurfaceView 源碼概述
SurfaceView 主要用于處理需要高效、實(shí)時(shí)渲染的場(chǎng)景,例如視頻播放、游戲渲染、相機(jī)預(yù)覽等。它的渲染操作由后臺(tái)線程執(zhí)行,避免了與主 UI 線程的競(jìng)爭(zhēng),提升了性能。
主要類及源碼文件
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,然后注冊(cè)回調(diào)接口來處理 Surface 的生命周期。具體代碼如下:
public SurfaceView(Context context) {
super(context);
mSurfaceHolder = getHolder(); // 獲取 SurfaceHolder
mSurfaceHolder.addCallback(this); // 注冊(cè)回調(diào)
}在此過程中,getHolder() 返回一個(gè) SurfaceHolder 對(duì)象,該對(duì)象用于管理與 SurfaceView 關(guān)聯(lián)的 Surface。SurfaceHolder.Callback 回調(diào)接口的實(shí)現(xiàn)幫助我們?cè)?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)勢(shì)。
2.1 TextureView 使用示例
下面是一個(gè)簡(jiǎn)單的 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ì)象用于接收?qǐng)D形數(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)畫或變換需要依賴外部圖形庫(kù)如 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 生命周期 |
| 適用場(chǎng)景 | 適用于視頻播放、實(shí)時(shí)游戲渲染等對(duì)性能要求高的應(yīng)用 | 適用于動(dòng)態(tài)變換、動(dòng)畫和需要與 UI 層交互的場(chǎng)景(如視頻展示、圖像旋轉(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)容更新較為簡(jiǎn)單,依賴 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)、縮放等變換,需使用外部圖形庫(kù) | 支持內(nèi)建旋轉(zhuǎn)、縮放和其他變換,支持多種變換方式 |
| API 支持 | 支持大部分 Android 設(shè)備,并且對(duì)硬件解碼支持較好 | 支持大部分 Android 設(shè)備,適合需要在視圖層做渲染處理的場(chǎng)景 |
| 渲染線程 | 在獨(dú)立線程中進(jìn)行渲染,UI 線程與渲染分離 | 渲染在 UI 線程中進(jìn)行,UI 操作與渲染共用一個(gè)線程 |
到此這篇關(guān)于Android的SurfaceView和TextureView介紹的文章就介紹到這了,更多相關(guān)Android SurfaceView和TextureView內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(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-10
android studio使用SQLiteOpenHelper()建立數(shù)據(jù)庫(kù)的方法
這篇文章主要介紹了android studio使用SQLiteOpenHelper()建立數(shù)據(jù)庫(kù)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Android關(guān)于BottomNavigationView使用指南
本文主要介紹了Android關(guān)于BottomNavigationView使用指南,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Android中獲得正在運(yùn)行的程序和系統(tǒng)服務(wù)的方法
這篇文章主要介紹了Android中獲得正在運(yùn)行的程序和系統(tǒng)服務(wù)的方法,分別是對(duì)ActivityManager.RunningAppProcessInfo類和ActivityManager.RunningServiceInfo類的使用,需要的朋友可以參考下2016-02-02
Android編程設(shè)計(jì)模式之中介者模式詳解
這篇文章主要介紹了Android編程設(shè)計(jì)模式之中介者模式,結(jié)合實(shí)例形式詳細(xì)分析了Android中介者模式的概念、原理、使用場(chǎng)景、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2017-12-12
25個(gè)實(shí)用酷炫的Android開源UI框架
本文為大家分享了25個(gè)實(shí)用酷炫的Android開源UI框架,靈活運(yùn)用這些UI框架可在日常工作中節(jié)省不少時(shí)間2018-04-04
Android Studio中導(dǎo)入module的方法(簡(jiǎn)單版)
這篇文章主要介紹了AndroidStudio中導(dǎo)入module的方法,本文是一篇簡(jiǎn)易版的教程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-01-01

