目录
4.surfaceView ,Surface,SurfaceHolder 关系图
5.SurfaceView 使用小实例: 绘制正选曲线代码如下
8.textureView 和 SurfaceView使用总结:
学习surfaceView之前先了解以下surface的一些知识
1.surface定义:
Surfaces是用来处理屏幕显示内容合成器所管理的原始缓存区的工具。android在设计时基于共享内存设计了一套Surface机制,在应用程序这端,Surface可以简单的理解为绘制时用的画布,在程序中可以抽象为一块内存,应用程序绘制前通过WMS先在SurfaceFlinger申请一个Surface,然后就可以随意的绘制,绘制完之后,通知SurfaceFlinger将该Surface合成输出即可。
2.surfaceView 是什么?
它继承自类View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface,在WMS中有对应的WindowState,在SurfaceFlinger中有Layer。
我们知道,一般的Activity包含的多个View会组成View hierachy(view树形结构).只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的(根层是挂在窗体上的)。这个DecorView在WMS中有一个对应的WindowState。相应地,在SurfaceFlinger中对应的Layer。而SurfaceView自带一个Surface,这个Surface在WMS中有自己对应的WindowState,在SurfaceFlinger中也会有自己的Layer。虽然在App端surfaceView它仍在View hierachy中,但在Server端(WMS和SF)中,它与宿主窗口是分离的。这样的好处是对这个Surface的渲染可以放到单独线程去做。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换
3.surfaceView的双缓存机制
什么是缓冲:在我们的界面中图形都是在画布上绘制出来的,所以这个绘制过程就叫缓冲,而画布也可以称作缓冲区。
无缓冲:不使用画布的情况下直接在窗口上进行绘图就叫做无缓冲绘图。
单缓冲:用了一个画布,将所有的内容先绘制到画布上,再整体绘制到窗口,这个就叫做单缓冲绘图。Android中View的onDraw()方法已经实现了这一层缓冲。onDraw()方法中不是绘制一点显示一点,而是都绘制完后
双缓冲:用了两个画布,一个进行临时的绘图,一个进行最终的绘图,这样的就叫做双缓冲绘图。
onDraw()方法的Canvas对象是和屏幕关联的,而onDraw()方法是运行在UI线程中的,如果要绘制的图像过于复杂,则有可 能导致应用程序卡顿,甚至ANR。因此我们可以先创建一个临时的Canvas对象,将图像都绘制到这个临时的Canvas对象 中,绘制完成之后再将这个临时Canvas对象中的内容,绘制到要显示onDraw()方法中的canvas对象中。这样的话就相当于是一个拷贝过程,比直接绘制效率要高,可以减少对UI线程的阻塞
SurfaceView在更新视图时用到了两张Canvas,一张frontCanvas(显示)和一张backCanvas(存储),每次实际显示的是frontCanvas,backCanvas存储的是上一次更改前的视图。通过使用SurfaceHolder的lockCanvas()获取画布,得到的实际上是backCanvas而不是正在显示的frontCanvas,之后在获取到的backCanvas上绘制新视图,再通过SurfaceHolder的unlockCanvasAndPost(canvas)方法将视图更新到显示的视图上,那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas,原来的frontCanvas将切换到后台作为backCanvas。
双缓存的优点:比直接绘制效率要高,相当于一个拷贝过程,可以减少对UI线程的阻塞,绘制特别及时没有延迟,可以把要绘制的数据放到子线程操作,提高效率。
4.surfaceView ,Surface,SurfaceHolder 关系图
此图展示了一个mvc的架构模式: 这3者之间其实是典型的MVC模式,其中SurfaceView对应的就是View层,SurfaceHolder就是controller接口,而Surface就是对应的Model层,它里面持有Canvas,保存着绘制的数据
调用接口如下图:
5.SurfaceView 使用小实例: 绘制正选曲线代码如下
package com.study.study.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/***
* surfaceView的使用;
*/
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback ,Runnable{
private SurfaceHolder mHolder;
private Canvas mCanvas;//绘图的画布
private boolean mIsDrawing;//控制绘画线程的标志位
public static final int TIME_IN_FRAME = 30;
private Path mPath;
private Paint mPaint;
private int x = 0, y = 0;
public MySurfaceView(Context context) {
super(context);
init();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(5);
mPath = new Path();
//路径起始点(0, 100)
mPath.moveTo(0, 100);
//获取创建的surfaceHolder
mHolder = getHolder();
//设置回调监听
mHolder.addCallback(this);
//设置有焦点
setFocusable(true);
setFocusableInTouchMode(true);
//屏幕常亮;
this.setKeepScreenOn(true);
}
/************以下实现surfaceHolder.callback的接口回调******************/
@Override
public void surfaceCreated(SurfaceHolder holder) {
//表示surfaceView创建成功可用,
//设置标志位
mIsDrawing = true;
//创建子线程;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//界面销毁
//移除标志位
mIsDrawing=false;
}
/**---------------------------以下实现runnable方法的回调开子线程------------------------------------**/
@Override
public void run() {
//在子线程中进行绘画操作
while (mIsDrawing) {
//进行绘制
doDrawSometing();
x += 1;
y = (int)(100 * Math.sin(2 * x * Math.PI / 180) + 400);
//加入新的坐标点
mPath.lineTo(x, y);
}
}
private void doDrawSometing() {
synchronized (mHolder) {
try{
mCanvas=mHolder.lockCanvas();//获取Canvas对象进行绘制
//SurfaceView背景
mCanvas.drawColor(Color.WHITE);
mCanvas.drawPath(mPath,mPaint);
}catch (Exception e){
e.printStackTrace();
}finally {
if (mCanvas!=null){
mHolder.unlockCanvasAndPost(mCanvas);//保证绘制的画布内容提交
}
}
}
}
}
测试结果:
6.SurfaceView 总结:
优点:可以在一个独立的线程中进行绘制,不会影响主线程
使用双缓冲机制,播放视频时画面更流畅 没有延迟现象
缺点:Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中。SurfaceView 不能嵌套使用
7.TextureView是什么
在4.0(API level 14)中引入,与SurfaceView一样继承View, 它可以将内容流直接投影到View中,它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同,它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。值得注意的是TextureView必须在硬件加速的窗口中。它显示的内容流数据可以来自App进程或是远端进程。TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。Surface为BufferQueue的Producer接口实现类,使生产者可以通过它的软件或硬件渲染接口为SurfaceTexture内部的BufferQueue提供graphic buffer。
7.1TextureView优点及缺点
优点:支持移动、旋转、缩放等动画,支持截图
缺点:必须在硬件加速的窗口中使用,占用内存比SurfaceView高,
在5.0以前在主线程渲染,5.0以后有单独的渲染线程。
8.textureView 和 SurfaceView使用总结:
1、在android 7.0上系统surfaceview的性能比TextureView更有优势,支持对象的内容位置和包含的应用内容同步更新,平移、缩放不会产生黑边。 在7.0以下系统如果使用场景有动画效果,可以选择性使用TextureView
2、由于失效(invalidation)和缓冲的特性,TextureView增加了额外1~3帧的延迟显示画面更新
3、TextureView总是使用GL合成,而SurfaceView可以使用硬件overlay后端,可以占用更少的内存带宽,消耗更少的能量
4、TextureView的内部缓冲队列导致比SurfaceView使用更多的内存