Android SurfaceView 组件介绍,挖洞原理详解
文章目录
- 组件介绍
- 基本概念
- 关键特性
- 使用场景
- SurfaceHolder介绍
- 主要功能
- 使用示例
- SurfaceView 挖洞原理
- 工作机制
- 使用SurfaceView展示图片示例
- 创建一个自定义的 SurfaceView类
- 在 Activity 中使用 ImageSurfaceView
- 注意事项
- 效果展示
组件介绍
在 Android 开发中,SurfaceView 是一个非常特别的组件,它提供了一个专门的绘制表面,允许在主线程之外的线程上进行绘制操作。这使得 SurfaceView 非常适合需要高性能绘制和更新的场景,如视频播放和游戏渲染。这是因为它可以减少和避免 UI 线程的阻塞和延迟。
基本概念
SurfaceView 继承自 View 类,但与普通的 View 不同,它内部使用了一个独立的绘图表面(即 Surface),这个 Surface 可以在主 UI 线程之外的线程上进行控制和绘制。这样做的好处是,即使绘制操作很复杂,也不会影响到 UI 线程的响应性和流畅性。
关键特性
-
独立的绘图表面:
SurfaceView的Surface是独立于应用窗口的其余部分,并且可以在单独的线程中进行更新和渲染。这意味着它不会受到其他视图层级更新的影响,从而提高了渲染效率。
-
线程安全:
- 由于
Surface可以从任何线程进行访问和修改,因此SurfaceView特别适用于后台线程渲染内容,如视频播放和动态图形。
- 由于
-
可见性管理:
SurfaceView在屏幕上的可见性由 Android 的窗口管理器直接处理。当SurfaceView变为不可见时,它的Surface可能会被销毁,因此开发者需要在适当的生命周期回调中管理资源和绘制状态。
使用场景
- 视频播放:
SurfaceView常用于视频播放应用,因为视频解码和渲染可以在单独的线程上进行,避免 UI 线程阻塞。 - 实时游戏渲染:游戏中的图形渲染需要高频率的更新和高性能,
SurfaceView提供的独立绘图表面能够满足这些要求。 - 相机预览:相机应用中,
SurfaceView可用于显示相机的实时预览流。
SurfaceHolder介绍
在Android开发中,SurfaceHolder是一个接口,用于控制和监视Surface对象的状态。Surface是一个特殊的对象,它承载了一个可以绘制的矩形区域。这个区域可以由你的应用程序或其他应用程序来绘制。SurfaceView类就是围绕Surface提供一个可视组件的实现,而SurfaceHolder提供了对这个Surface的控制和管理。
主要功能
1. 访问和控制Surface:
SurfaceHolder允许开发者直接访问Surface对象,这意味着你可以管理和绘制到Surface上的图形内容。通过SurfaceHolder,你可以获取Surface的Canvas,并在这个Canvas上进行绘制操作。
2. 监听Surface的状态变化:
SurfaceHolder提供了一个回调机制,通过实现SurfaceHolder.Callback接口,你可以监听Surface的创建、改变和销毁事件。这些回调方法是:surfaceCreated(SurfaceHolder holder): 当Surface第一次创建时调用,你应该在这个回调中开始绘制的操作。surfaceChanged(SurfaceHolder holder, int format, int width, int height): 当Surface的格式或大小发生变化时调用。surfaceDestroyed(SurfaceHolder holder): 当Surface即将被销毁时调用,你应该在这个回调中停止绘制操作,并进行清理。
3. 控制Surface的格式和尺寸:
SurfaceHolder允许开发者设置Surface的尺寸、格式和类型。例如,你可以指定Surface的分辨率和颜色深度。
使用示例
在使用SurfaceView时,你通常会与SurfaceHolder打交道。
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {private SurfaceHolder surfaceHolder;private DrawingThread drawingThread;public MySurfaceView(Context context) {super(context);init();}private void init() {surfaceHolder = getHolder();surfaceHolder.addCallback(this);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {drawingThread = new DrawingThread(holder);drawingThread.setRunning(true);drawingThread.start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {// Handle changes}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {boolean retry = true;drawingThread.setRunning(false);while (retry) {try {drawingThread.join();retry = false;} catch (InterruptedException e) {// handle interruption}}}private class DrawingThread extends Thread {private SurfaceHolder surfaceHolder;private boolean isRunning = false;public DrawingThread(SurfaceHolder holder) {this.surfaceHolder = holder;}public void setRunning(boolean isRunning) {this.isRunning = isRunning;}@Overridepublic void run() {while (isRunning) {Canvas canvas = null;try {canvas = surfaceHolder.lockCanvas();synchronized (surfaceHolder) {if (canvas != null) {// Perform drawing on the canvas}}} finally {if (canvas != null) {surfaceHolder.unlockCanvasAndPost(canvas);}}}}}
}
SurfaceHolder是一个非常强大的工具,它为Surface的管理提供了广泛的控制功能,同时使得在单独的线程中进行复杂的绘图操作成为可能,从而不影响应用程序的主UI线程的响应性。这在需要高性能绘图更新,如游戏或媒体播放器等应用中尤其重要。
SurfaceView 挖洞原理
在 Android 中,SurfaceView 是一个用于直接绘制图形的视图,通常用于游戏或视频播放等高性能需求的应用场景。SurfaceView 的挖洞原理主要涉及到 SurfaceView 的工作机制和它与窗口系统之间的交互。
工作机制
-
双缓冲机制:
SurfaceView使用双缓冲机制,即前缓冲区和后缓冲区。前缓冲区显示在屏幕上,后缓冲区用于绘制新的内容。当后缓冲区绘制完成后,前后缓冲区交换,新的内容就会显示在屏幕上。这种机制可以减少屏幕闪烁和绘制延迟。 -
独立 Surface:
SurfaceView创建了一个独立的 Surface,它与主 UI 线程分离,允许在另一个线程上进行绘制操作。这使得在 SurfaceView 上进行复杂的图形绘制时不会阻塞主 UI 线程,提高了绘制性能。 -
SurfaceHolder:
SurfaceView通过SurfaceHolder来管理其 Surface 的生命周期和绘制操作。SurfaceHolder提供了一系列的回调方法,例如surfaceCreated、surfaceChanged和surfaceDestroyed,用于监听 Surface 的创建、改变和销毁。
SurfaceView 挖洞的原理实际上是利用了 SurfaceView 绘制的特性,通过创建一个透明或空洞的区域,使得底层的内容可以透过 SurfaceView 显示出来。具体步骤如下:
-
设置透明背景:将
SurfaceView的背景设置为透明,使得 SurfaceView 背景区域不绘制任何内容,从而形成“挖洞”效果。<SurfaceViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/transparent" /> -
绘制透明区域:在 SurfaceView 的 Canvas 上绘制一个透明区域,使得该区域不会绘制任何内容,从而露出底层视图。例如,可以使用
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)方法清空指定区域。 -
层次叠加:利用视图的层次叠加关系,将
SurfaceView放置在其他视图之上,并通过透明区域露出下层视图的内容。例如,可以在 SurfaceView 下方放置一个 ImageView 或其他自定义视图,通过透明区域显示底层视图的内容。
以下是一个简单的代码示例,演示了如何在 SurfaceView 中实现透明区域(“挖洞”):
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {private Paint mPaint;private Rect mRect;public MySurfaceView(Context context) {super(context);getHolder().addCallback(this);mPaint = new Paint();mPaint.setColor(Color.RED); // 设置绘制颜色mRect = new Rect(100, 100, 300, 300); // 定义透明区域}@Overridepublic void surfaceCreated(SurfaceHolder holder) {draw();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}private void draw() {Canvas canvas = getHolder().lockCanvas();if (canvas != null) {canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // 清空整个画布canvas.drawRect(mRect, mPaint); // 绘制矩形区域getHolder().unlockCanvasAndPost(canvas);}}
}
这个示例创建了一个自定义的 SurfaceView,并在其中绘制了一个矩形区域。通过 PorterDuff.Mode.CLEAR 模式,可以清空指定区域,使得该区域变得透明,从而实现“挖洞”效果。
使用SurfaceView展示图片示例
要在 Android 中使用 SurfaceView 在单独的线程中展示一张图片,我们可以通过创建一个自定义的 SurfaceView 类来实现。
示例代码:
创建一个自定义的 SurfaceView类
这个类将包含加载图片和在 SurfaceView 上绘制图片的逻辑:
public class ImageSurfaceView extends SurfaceView implements SurfaceHolder.Callback {private DrawThread drawThread;private Bitmap imageBitmap;public ImageSurfaceView(Context context,int imageResource) {super(context);this.imageBitmap = BitmapFactory.decodeResource(context.getResources(),imageResource);getHolder().addCallback(this);}@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {//开启新线程 绘制图片drawThread = new DrawThread(getHolder(), imageBitmap);drawThread.setRunning(true);drawThread.start();}@Overridepublic void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {//停止绘制线程boolean retry = true;drawThread.setRunning(false);while (retry) {try {drawThread.join();retry = false;} catch (InterruptedException e) {e.printStackTrace();}}}//新开一个线程用来绘制图片到Canvasprivate class DrawThread extends Thread{private SurfaceHolder surfaceHolder;private boolean isRunning = false;private Bitmap imageBitmap;public DrawThread(SurfaceHolder holder,Bitmap imageBitmap) {this.surfaceHolder = holder;this.imageBitmap = imageBitmap;}public void setRunning(boolean isRunning) {this.isRunning = isRunning;}@Overridepublic void run(){while(isRunning){Canvas canvas = null;//尝试获取canvas 绘制图片try {canvas = surfaceHolder.lockCanvas();if (canvas != null) {synchronized (surfaceHolder) {//绘制图片canvas.drawBitmap(imageBitmap, 0, 0, null);}}}finally {if (canvas != null) {surfaceHolder.unlockCanvasAndPost(canvas);}}}}}}
在 Activity 中使用 ImageSurfaceView
import android.app.Activity;
import android.os.Bundle;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 替换 R.drawable.your_image 为你的实际图片资源ImageSurfaceView imageSurfaceView = new ImageSurfaceView(this, R.drawable.your_image);setContentView(imageSurfaceView);}
}
注意事项
- 确保你的图片资源位于
res/drawable文件夹中。 ImageSurfaceView类中的DrawThread在surfaceDestroyed方法被调用时应该被正确地停止,以避免可能的内存泄露或崩溃。- 这个例子展示了在一个单独的线程中加载和绘制图片,以避免阻塞 UI 线程。
效果展示

注:这个dmeo仅仅展示了SurfaceView 新开线程展示图片效果,学习SurfaceView渲染流程,无法应用实际开发,如果用于实际开发,如开发自定义控件,还需进一步完善自定义的类
相关文章:
Android SurfaceView 组件介绍,挖洞原理详解
文章目录 组件介绍基本概念关键特性使用场景 SurfaceHolder介绍主要功能使用示例 SurfaceView 挖洞原理工作机制 使用SurfaceView展示图片示例创建一个自定义的 SurfaceView类在 Activity 中使用 ImageSurfaceView注意事项效果展示 组件介绍 在 Android 开发中,Sur…...
day2加餐 Go 接口型函数的使用场景
文章目录 问题价值使用场景其他语言类似特性 问题 在 动手写分布式缓存 - GeeCache day2 单机并发缓存 这篇文章中,有一个接口型函数的实现: // A Getter loads data for a key. type Getter interface {Get(key string) ([]byte, error) }// A Getter…...
摄像头 RN6752v1 视频采集卡
摄像头 AHD倒车摄像头比较好,AHD英文全名Analog High Definition,即模拟高清,拥有比较好的分辨率与画面质感。 RN6752v1 GQW AKKY2 usb 采集卡 FHD(1080p)、HD(720p)和D1(480i&am…...
记录vivado自带IP iBert眼图近端回环
记录利用vivado自带IP核工具测试信号质量 ibert是测试眼图的工具,在使用的时候并不用改太多的内容,只需要注意参考时钟及所需要的引脚即可。由于条件的限制,并没有使用光纤和电缆进行连接进行外部回环,仅使用内部回环做测试&…...
js | Core
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/ Object 是什么? 属性[[prototype]]对象。 例如,下面的,son是对象,foo不是对象。打印出来的son,能看到有一个prototype 对象。 prototype vs _proto_ v…...
Log4J reminder
Java JNDI and Log injection https://docs.oracle.com/javase/jndi/tutorial/ See also https://telegra.ph/Log4J-Vulnerability-Explained-07-21...
Unity XR Interaction Toolkit(VR、AR交互工具包)记录安装到开发的流程,以及遇到的常见问题(一)!
提示:文章有错误的地方,还望诸位大神不吝指教! 文章目录 前言一、XR Interaction Toolkit是什么?二、跨平台交互三、 AR 功能四、XR Interaction Toolkit的特点五、XR Interaction Toolkit 示例总结 前言 随着VR行业的发展&#…...
MongoDB文档整理
过往mongodb文档: https://blog.csdn.net/qq_46921028/article/details/123361633https://blog.csdn.net/qq_46921028/article/details/131136935https://blog.csdn.net/qq_46921028/article/details/139247847 1. MongoDB前瞻 1、MongoDB概述: MongoDB是…...
【AI学习】关于Scaling Law的相关学习
一、苦涩的教训 首先,学习一段重要话语: The biggest lesson that can be read from 70 years of AI research is that general methods that leverage computation are ultimately the most effective, and by a large margin. 从70年的人工智能研究中…...
学习小记-Kafka相较于其他MQ有啥优势?
Kafka 相比于 RocketMQ 有以下几个优势: 1. 高吞吐量和低延迟: Kafka 以其出色的 I/O 性能和分布式架构设计,能够实现极高的吞吐量,每秒数百万的消息处理能力,适合大规模数据流处理。同时,Kafka 设计为…...
技能 | postman接口测试工具安装及使用
哈喽小伙伴们大家好!今天来给大家分享一款轻量级,高效好用的接口测试工具-postman. Postman是一个流行的API开发工具,主要用于测试、开发和文档化API。以下是关于Postman的介绍及其主要使用场景: Postman介绍: 1. 功能丰富的API客户端&#…...
移动UI:任务中心的作用,该如何设计更合理?
任务中心是移动应用中用于展示和管理用户待办任务、提醒事项、用户福利、打卡签到等内容的功能模块。合理设计任务中心可以提升用户体验和工作效率。 以下是一些设计任务中心的合理建议: 1. 易于查看和管理: 任务中心的设计应该使用户能够快速、直观地…...
pytorch学习(十)优化函数
优化函数主要有,SGD, Adam,RMSProp这三种,并且有lr学习率,momentum动量,betas等参数需要设置。 通过这篇文章,可以学到pytorch中的优化函数的使用。 1.代码 代码参考《python深度学习-基于pytorch》&…...
Ubuntu22.04:安装Samba
1.安装Samba服务 $ sudo apt install samba samba-common 2.创建共享目录 $ mkdir /home/xxx/samba $ chmod 777 /home/xxx/samba 3.将用户加入到Samba服务中 $ sudo smbpasswd -a xxx 设置用户xxx访问Samba的密码 4.配置Samba服务 $ sudo vi /etc/samba/smb.conf 在最后加入 …...
Powershell 使用介绍
0 Preface/Foreword 0.1 参考文档 Starting Windows PowerShell - PowerShell | Microsoft Learn 1 Powershell 介绍 2 命令介绍 2.1 新建文件夹 New-Item -Path C:\GitLab-Runner -ItemType Directory 2.2 切换路径 cd C:\GitLab-Runner 2.3 下载文件 Invoke-WebRequ…...
【Langchain大语言模型开发教程】记忆
🔗 LangChain for LLM Application Development - DeepLearning.AI 学习目标 1、Langchain的历史记忆 ConversationBufferMemory 2、基于窗口限制的临时记忆 ConversationBufferWindowMemory 3、基于Token数量的临时记忆 ConversationTokenBufferMemory 4、基于历史…...
最新Qt6的下载与成功安装详细介绍
引言 Qt6 是一款强大的跨平台应用程序开发框架,支持多种编程语言,最常用的是C。Qt6带来了许多改进和新功能,包括对C17的支持、增强的QML和UI技术、新的图形架构,以及构建系统方面的革新。本文将指导你如何在Windows平台上下载和安…...
LeetCode 热题 HOT 100 (001/100)【宇宙最简单版】
【链表】 No. 0160 相交链表 【简单】👉力扣对应题目指路 希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#x…...
Ubantu 使用 docker 配置 + 远程部署 + 远程开发
大家好我是苏麟 , Ubantu 一些配置 . 视频 : 服务器很贵?搞台虚拟机玩玩!保姆级 Linux 远程开发教程_哔哩哔哩_bilibili Docker安装及配置 安装命令 : sudo apt install docker.io 查看版本号 : docker -v 查看虚拟机地址命令 : ifconfig 虚拟机地址 或…...
应用层自定义协议与序列化
个人主页:Lei宝啊 愿所有美好如期而遇 协议 简单来说,就是通信双方约定好的结构化的数据。 序列化与反序列化 我们通过一个问题引入这个概念,假如我们要实现一个网络版的计算器,那么现在有两种方案,第一种&#x…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
