Android音频开发之SurfaceView的使用详解
作者:JulyYu 发布时间:2023-01-15 13:56:43
SurfaceView
SurfaceView
从源码上看继承自View
,但在内部实现上SurfaceView
和其他View
有很多区别。 SurfaceView
主要作用是提供一个直接绘图表面嵌入到视图结构中,实际上真正做绘制能力的是Surface
。因此SurfaceView
和宿主窗口是分离的。正常情况下窗口的View
共享同一个Window
,而Window
也对应一个Surface
,所有View
也就共享同一个Surface
。所以SurfaceView
具备独立的Surface
,相当于和宿主窗口绘制是分离互不干扰。
不同点
不同点 | SurfaceView | View |
---|---|---|
绘制 | 结构在View当中,但绘制表面是独立的。内部拥有自己的Canvas进行绘制操作 | 和宿主窗口共享同一个绘图表面 |
刷新 | 窗口刷新不需要重绘宿主窗口 | 任何一个子元素或是局部刷新都会使得整个视图结构发生重绘 |
线程 | 线程独立,不影响主线程 使用界面频繁刷新 | 在UI主线程使用 |
操作 | 低版本不支持平移、缩放、旋转等动画 不具备View属性控制 | 均可正常操作 |
刷新 | 可控制刷新频率、双缓存机制 | 只在主线程刷新更新 |
双缓冲机制
SurfaceView
将视频流解析成一帧帧图像数据显示。例如一帧图像显示后,等待下一帧图像可能存在还未及时解析的情况,这种情况下就会导致画面不流畅。利用双缓冲可以避免这种情况,可以理解双缓冲是两个线程轮流解析视频流图像数据两者交替进行解析和渲染操作从而保证视频流能够流畅播放。
SurfaceHolder
SurfaceView
双缓冲机制事实上是比较消耗系统内存。因此当SurfaceView
在不可见状态下就会去销毁SurfaceHolder
来减轻内存开销。因此就有了SurfaceHolder
的addCallback
方法来监听SurfaceHolder
状态。
void surfaceCreated(@NonNull SurfaceHolder holder); 创建回调
void surfaceChanged(@NonNull SurfaceHolder holder, @PixelFormat.Format int format, @IntRange(from = 0) int width, @IntRange(from = 0) int height); 修改回调
void surfaceDestroyed(@NonNull SurfaceHolder holder); 销毁回调
使用
自定义继承SurfaceView
可以自定义绘制内容。当创建SurfaceHolder
成功后再surfaceCreated
回调中调用lockCanvas
获取到SurfaceHolder
的画布并锁定,然后绘制内容。绘制结束后调用unlockCanvasAndPost
释放并提交画布改动信息,让新数据在画布上进行展示。
public class SurfaceViewTest extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mSurfaceHolder;
private Canvas mCanvas;
private Paint paint;
public SurfaceViewTest(Context context) {
this(context,null,0);
}
public SurfaceViewTest(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SurfaceViewTest(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mSurfaceHolder = getHolder(); // 初始化
mSurfaceHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 创建成功后就能通过线程绘制自定义内容
new Thread(new Runnable() {
@Override
public void run() {
draw();
}
}).start();
}
private void draw() {
try {
mCanvas = mSurfaceHolder.lockCanvas();
mCanvas.drawCircle(500,500,300,paint);
mCanvas.drawCircle(100,100,20,paint);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mCanvas != null)
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
}
来源:https://juejin.cn/post/7086047678727585822


猜你喜欢
- 代码思路:想要循环遍历文件夹下所有子文件夹,就要用到递归。首先判断路径是否存在:是:获取文件判断是否文件夹:是:调用自身,继续获取子文件夹下
- Android提供了对常用音频和视频格式的支持,它所支持的音频格式有MP3(.mp3)、3GPP(.3gp)、Ogg(.ogg)和WAVE(
- 由于jdk 1.8 之后sun.misc 包下的 BASE64Decode的依赖 被移除我们需要在自己的项目中引入EncodeUtils 工
- 概述异步这个概念在不同语境下有不同的解释,比如在一个单核CPU里开启两个线程执行两个函数,通常认为这种调用是异步的,但对于CPU来说它是单核
- 本文实例讲述了C#实现基于IE内核的简单浏览器。分享给大家供大家参考。具体如下:Form1.cs如下:using System;using
- 在Android中,Activity主要负责前台页面的展示,Service主要负责需要长期运行的任务,所以在我们实际开发中,就会常常遇到Ac
- 前言在开始介绍socket前先补充补充基础知识,在此基础上理解网络通信才会顺理成章,当然有基础的可以跳过去了。都是废话,进入正题。TCP/I
- C#编写winform程序时,用到的,格式强转,存储到数据库,数据库连接那块就不写了希望对大家有帮助,欢迎评论互相分享技术!//日期格式强制
- Spring在Java EE开发中是实际意义上的标准,但我们在开发Spring的时候可能会遇到以下令人头疼的问题:(1)大量配置文件的定义;
- 这篇文章主要介绍了Java 比较接口comparable与comparator区别解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作
- maven导入依赖<dependencies> <dependency> &
- 前言本篇开始讲解音频编辑的具体操作,从相对简单的音频裁剪开始。要进行音频裁剪,我的方案是开启一个Service服务用于音频裁剪的耗时操作,主
- 一、算术运算符运算符:常见的±*/等表达式:运算符连接起来符合java语法的式子,比如a+b算术运算符:+ - * / %注:要想得到小数,
- Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsof
- 给新建的winform程序添加资源文件夹Resources小菜鸟开始学习WinForm程序别人的项目都有资源文件夹放图片之类的,我的就是没有
- 一、概要线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就是成为整体的必用方案之一。可以说,使线程
- C#实现委托namespace Delegate{ delegate void DGSayiHi(string n
- 直接上代码,代码中使用四种方法遍历Hashtable。using System;using System.Collections;names
- 1.场景线程池使用DiscardOldestPolicy拒绝策略,阻塞队列使用ArrayBlockingQueue,发现在某些情形下对于得到
- 本文实例为大家分享了Android实现聊天界面的具体代码,供大家参考,具体内容如下文件目录在app下的build.gradle中添加依赖库(