Android中提供了View进行绘图处理,View可以满足大部分的绘图需求,但是有时候,View却显得力不从心,所以Android提供了SurfaceView给Android开发者,以满足更多的绘图需求。下面就让我们一起来了解一下SurfaceView。
View和SurfaceView的区别
1 . View适用于主动更新的情况,而SurfaceView则适用于被动更新的情况,比如频繁刷新界面。
2 . View在主线程中对页面进行刷新,而SurfaceView则开启一个子线程来对页面进行刷新。
3 . View在绘图时没有实现双缓冲机制,SurfaceView在底层机制中就实现了双缓冲机制。
为什么使用SurfaceView?通俗来讲
- 如果屏幕刷新频繁,onDraw方法会被频繁的调用,onDraw方法执行的时间过长,会导致掉帧,出现页面卡顿。而SurfaceView采用了双缓冲技术,提高了绘制的速度,可以缓解这一现象。
- view的onDraw方法是运行在主线程中的,会轻微阻塞主线程,对于需要频繁刷新页面的场景,而且onDraw方法中执行的操作比较耗时,会导致主线程阻塞,用户事件的响应受到影响,也就是响应速度下降,影响了用户的体验。而SurfaceView可以在自线程中更新UI,不会阻塞主线程,提高了响应速度。
双缓冲技术
双缓冲技术是游戏开发中的一个重要的技术。当一个动画争先显示时,程序又在改变它,前面还没有显示完,程序又请求重新绘制,这样屏幕就会不停地闪烁。
双缓冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上。
双缓冲主要是为了解决 反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里,然后整体的一次性画出来。
SurfaceView用法
通过lockCanvas()方法获得Canvas对象
在子线程中使用Canvas对象进行绘制
使用unlockCanvasAndPost()方法将画布内容进行提交
注意: lockCanvas() 方法获得的Canvas对象仍然是上次绘制的对象,由于我们是不断进行绘制,但是每次得到的Canvas对象都是第一次创建的Canvas对象。
public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder mSurfaceHolder;
//绘图的Canvas
private Canvas mCanvas;
//子线程标志位
private boolean mIsDrawing;
public SurfaceViewTemplate(Context context) {
this(context, null);
}
public SurfaceViewTemplate(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
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;
}
@Override
public void run() {
while (mIsDrawing){
drawSomething();
}
}
//绘图逻辑
private void drawSomething() {
try {
//获得canvas对象
mCanvas = mSurfaceHolder.lockCanvas();
//绘制背景
mCanvas.drawColor(Color.WHITE);
//绘图
}catch (Exception e){
}finally {
if (mCanvas != null){
//释放canvas对象并提交画布
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
}
/**
* 初始化View
*/
private void initView(){
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
setFocusable(true);
setKeepScreenOn(true);
setFocusableInTouchMode(true);
}
}
TextureView与SurfaceView区别
TextureView和SurfaceView都是继承自View类的,但是与其它View不同的是,两者都能在独立的线程中绘制和渲染,在专用的GPU线程中大大提高渲染的性能。子线程更新UI,也是相交于普通View的优势所在。
-
SurfaceView
专门提供了嵌入视图层级的绘制界面,开发者可以控制该界面像Size等的形式,能保证界面在屏幕上的正确位置。局限:
- 由于是独立的一层View,更像是独立的一个Window,不能加上动画、平移、缩放
- 两个SurfaceView不能相互覆盖。
-
TextureView
更像是一般的View,像TextView那样能被缩放、平移,也能加上动画。
局限:- 只能在开启了硬件加速的Window中使用,并且消费的内存要比SurfaceView多,并伴随着1-3帧的延迟。
- TextureView在Andriod4.0之后的API中才能使用
子线程UI更新方法
方法 | |
---|---|
SurfaceView | SurfaceHolder.addCallback |
TextureView | TextureView.setSurfaceTextureListener |
- 画面更新方式
- SurfaceView:双缓冲功能使画面更加流畅,但是由于其holder的存在导致画面更新会存在间隔。同时也不能进行像View一样的setAlpha和setRotation方法,但是对于需要不断告诉更新画布的应用是极好的选择。
- TextureView:更加适合视频播放器或相机应用的开发