Android的SurfaceView和TextureView介紹

文章目錄

  • 前言
  • 一、什么是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 來將圖像渲染到屏幕上。以下是該渲染流程的關鍵步驟:

  1. 初始化 SurfaceTexture 和 Surface:

TextureView 在初始化時創建一個 SurfaceTexture 對象,該對象用于接收圖形數據。
然后將 SurfaceTexture 封裝為 Surface,Surface 用于顯示圖像內容。

  1. 圖像數據傳遞到 SurfaceTexture:

圖形引擎(如 OpenGL)將渲染結果傳遞給 SurfaceTexture,這些數據會被存儲在 SurfaceTexture 中。

3.SurfaceTexture 更新:

一旦 SurfaceTexture 中的圖像數據更新,TextureView 會收到通知,并準備將新圖像內容顯示出來。
SurfaceTexture 會將最新的圖像數據傳遞給關聯的 Surface。

  1. 顯示圖像內容:

Surface 在 TextureView 上渲染和顯示圖像內容。此時,TextureView 會將圖像數據呈現到屏幕上。

三、SurfaceView和TextureView區別

特性SurfaceViewTextureView
渲染方式渲染內容直接通過硬件層輸出,不經過 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 操作與渲染共用一個線程

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/62602.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/62602.shtml
英文地址,請注明出處:http://en.pswp.cn/web/62602.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vscode 排除文件夾搜索

排除的文件夾 node_modules/,dist/

優雅的@ObservedV2和@Trace裝飾器

Hello&#xff0c;大家好&#xff0c;我是 V 哥。在HarmonyOS NEXT開發中&#xff0c;ObservedV2裝飾器和Trace裝飾器是用于狀態管理的兩個裝飾器&#xff0c;它們在HarmonyOS應用開發中用于增強對類對象中屬性的觀測能力。如果你學過觀察者模式的原理&#xff0c;你會更容易理…

備戰藍橋第一天 驗證回文串 楊輝三角

LCR 018. 驗證回文串 - 力扣&#xff08;LeetCode&#xff09; 涉及的函數&#xff1a; int isalnum ( int c ); 檢查字符是否為字母數字 int tolower ( int c ); 將大寫字母轉換為小寫 void reverse (BidirectionalIterator first, BidirectionalIterator last); 反轉區域中…

【實戰】提升List性能方法有幾何

在內存中的 List<T> 上使用 LINQ 查詢時&#xff0c;加索引并不像數據庫那樣有內置支持&#xff0c;但可以通過以下方式提高查詢性能&#xff1a; 1. 手動構建索引 可以手動構建一個字典 (Dictionary<TKey, TValue>)&#xff0c;將需要查詢的字段作為鍵&#xff0…

一款免費、簡單、快速的JS打印插件,web 打印組件,基于JavaScript開發,支持數據分組,快速分頁批量預覽,打印,轉pdf,移動端,PC端

前言 在數字化辦公時代&#xff0c;打印需求呈現多樣化和復雜化的趨勢。現有的打印軟件往往存在cao作繁瑣、兼容性差、功能單一等問題&#xff0c;難以滿足現代企業高效、靈活的打印需求。 為了解決這些痛點&#xff0c;一款簡單、高效、多功能的打印插件成為了迫切需求。 介…

Python pywin32庫詳解

一、引言 在Python編程中&#xff0c;有時候需要與Windows操作系統進行交互&#xff0c;執行一些特定的系統操作或操作 Windows 應用程序。這時&#xff0c;pywin32庫就成為了一個非常強大的工具。pywin32庫提供了對Windows API的訪問&#xff0c;使得Python開發者能夠在Windo…

Uniapp的vue、nvue、uvue后綴名區別

在 UniApp 中&#xff0c;.vue、.nvue 和 .uvue 是不同的文件后綴名&#xff0c;每個文件格式的使用場景和兼容性略有不同。下面是每個文件后綴的詳細解釋以及它們的兼容性&#xff1a; 1. .vue 文件 定義&#xff1a;.vue 是標準的 Vue 單文件組件格式&#xff0c;主要用于基…

TCP/IP雜記

TCP三次握手、四次揮手 從應用角度&#xff0c;不用多考慮為什么有三次&#xff0c;遵循標準即可。 ubuntu 下 wireshark安裝&#xff1a; sudo add-apt-repository universe sudo apt install wireshark 三次握手實證&#xff1a; 第一次握手的情況如下&#xff1a;&#…

Vue前端開發-接收跳轉參數

路由攜帶參數跳轉到目標頁面后&#xff0c;頁面組件可以接收到攜帶傳入的參數&#xff0c;接收的方式與攜帶的方式相關&#xff0c;如果是采用查詢字符串方式攜帶&#xff0c;那么可以通過路由中的query對象獲取到參數&#xff0c;如果是其他方式&#xff0c;通常都是通過路由中…

力扣--LCR 177.撞色搭配

題目 整數數組 sockets 記錄了一個襪子禮盒的顏色分布情況&#xff0c;其中 sockets[i] 表示該襪子的顏色編號。禮盒中除了一款撞色搭配的襪子&#xff0c;每種顏色的襪子均有兩只。請設計一個程序&#xff0c;在時間復雜度 O(n)&#xff0c;空間復雜度O(1) 內找到這雙撞色搭配…

[ComfyUI]批量生成圖片的節點:輸入一個prompt列表批量生成圖像

文章目錄 1.參考資料2.兩個節點的部署FizzNodes節點comfyui-mixlab-nodes 生成的結果展示 1.參考資料 如何使用ComfyUI一次批量生成不同內容的圖片 ComfyUI工作流】隨機提示詞批量出圖&#xff0c;懶人刷圖福音&#xff0c;根據提示 2.兩個節點的部署 FizzNodes節點 fizzn…

【實操GPT-SoVits】聲音克隆模型圖文版教程

項目github地址&#xff1a;https://github.com/RVC-Boss/GPT-SoVITS.git官方教程&#xff1a;https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/tkemqe8vzhadfpeu本文旨在迅速實操GPT-SoVits項目&#xff0c;不闡述技術原理&#xff08;后期如果有時間研究&#…

5G模組AT命令腳本-關閉模組的IP過濾功能

關閉模組的IP過濾功能 關閉模組的IP過濾功能 5G 模組通常使用nat方式為 下掛設備或上位機提供上網服務&#xff0c;默認情況&#xff0c;不做NAt的包無法經由 模組轉發&#xff0c;如果禁掉這個限制 &#xff0c;可使用本文中的配置命令本腳本用于關閉模組的IP過濾功能&#xf…

JAVA (Springboot) i18n國際化語言配置

JAVA i18n國際化語言配置 一、簡介二、功能三、Java配置國際化步驟四、Java國際化配置工具類五、Spring Boot配置六、測試 一、簡介 在Java中&#xff0c;國際化&#xff08;Internationalization&#xff0c;通常簡稱為i18n&#xff09;是一個過程&#xff0c;它允許應用程…

如何創建基于udp的客戶端和服務端

1.先創建好udpServer.hpp、udpServer.cc、udpClient.hpp、udpClient.cc的框架。 #pragma once #include <string> #include <iostream> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <cerrno> #include…

【上線文檔】系統上線方案模板,計算機系統上線保障計劃,系統運維信息系統運行保障方案,系統上線方案模板(Word原件)

一、項目背景和目標 二、項目需求分析 2.1 功能需求 2.2 非功能需求 三、系統設計 3.1 系統架構設計 3.2 數據庫設計 3.3 接口設計 3.4 用戶界面設計 四、系統開發 4.1 開發環境搭建 4.2 業務邏輯開發 4.3 數據庫實現 4.4 接口實現 4.5 用戶界面實現 五、系統測…

大模型應用的數字能源數據集

除了尚須時日的量子計算解決算力效率和能源問題&#xff0c;以及正在路上的超越transformer的全新模型架構外&#xff0c;無疑是“數據集”&#xff0c;準確講是“高質量大規模多樣性的數據集”。數據集是大模型發展的核心要素之一&#xff0c;是大計算的標的物&#xff0c;是實…

【OpenCV】圖像轉換

理論 傅立葉變換用于分析各種濾波器的頻率特性。對于圖像&#xff0c;使用 2D離散傅里葉變換&#xff08;DFT&#xff09; 查找頻域。快速算法稱為 快速傅立葉變換&#xff08;FFT&#xff09; 用于計算DFT。 Numpy中的傅立葉變換 首先&#xff0c;我們將看到如何使用Numpy查…

如何使用Java編寫Jmeter函數

Jmeter 自帶有各種功能豐富的函數&#xff0c;可以幫助我們進行測試&#xff0c;但有時候提供的這些函數并不能滿足我們的要求&#xff0c;這時候就需要我們自己來編寫一個自定義的函數了。例如我們在測試時&#xff0c;有時候需要填入當前的時間&#xff0c;雖然我們可以使用p…

【2024版】最新kali linux入門及常用簡單工具介紹(非常詳細)從零基礎入門到精通,看完這一篇就夠了

前言 相信很多同學了解到和學習網絡安全的時候都聽過kali系統&#xff0c;大家都稱之為黑客最喜愛的系統&#xff0c;那么什么是kali&#xff0c;初學者用kali能做些什么&#xff0c;大白我將在本文中做詳細的介紹&#xff1a; 一、kali linux是什么&#xff1f; Kali Linux…