Android的绘图机制是由UI线程在屏幕上绘图,一般情况下不允许其他线程直接做绘图操作。这个机制在处理简单页面时没什么问题,因为普通页面不会频繁且大面积地绘图,但是该机制在处理复杂多变的页面时会产生问题,比如时刻变化着的游戏界面、拍照或录像时不断变换着的预览界面就会导致UI线程资源堵塞,即界面卡死的状况。
表面视图SurfaceView是Android用来解决子线程绘图的特殊视图,拥有独立的绘图表面,即不与其宿主页面共享同一个绘图表面。由于拥有独立的绘图表面,因此表面视图的界面能够在一个独立线程中进行绘制,这个子线程为渲染线程。因为渲染线程不占用主线程资源,所以一方面可以实现复杂而高效的UI刷新,另一方面及时响应用户的输入事件。由于表面视图具备以上特性,因此可用于拍照和录像的预览界面,也可用于游戏的实时界面。
因为表面视图不在UI主线程绘图,无论是onDraw方法还是dispatchDraw方法都没有进行绘图操作,所以表面视图必然要通过其他途径绘图,这个途径便是内部类表面持有者SurfaceHolder,外部调用SurfaceView对象的 getHolder方法获得 SurfaceHolder对象,然后进行预览界面的相关绘图操作。
下面是SurfaceHolder的常用方法:
lockCanvas:锁定并获取绘图表面的画布,返回值为Canvas。
unlockCanvasAndPost:解锁并刷新绘图表面的画布。
addCallback:添加绘图表面的回调接口 SurfaceHolder.Callback。回调接口有以下3个方法:
- (1) surfaceCreated:在绘图表面创建后触发,可在此打开相机。
- (2) surfaceChanged:在绘图表面变更后触发。
- (3) surfaceDestroyed:在绘图表面销毁后触发。
removeCallback:移除绘图表面的回调接口。
isCreating:判断绘图表面是否有效。如果在别处操作SurfaceView,就要判断当前绘图表面是否有效。
getSurface:获取绘图表面的对象,即预览界面。
setFixedSize:设置预览界面的尺寸。
setFormat:设置绘图表面的格式。绘图表面的格式一般有以下三种取值:
- (1) PixelFormat.TRANSPAREN 透明
- (2) PixelFormat.TRANSLUCENT 半透明
- (3) PixelFromat.OPAQUE 不透明
SurfaceView绘图案例:
锁定并获取画布 -> 绘制 -> 解锁画布
//获取SurfaceView控件
surfaceView=findViewById(R.id.surfaceView);
//获取持有者
SurfaceHolder surfaceHolder=surfaceView.getHolder();
//添加回调
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
//创建成功时调用
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
//准备画布
Canvas canvas=surfaceHolder.lockCanvas();
//准备画笔
Paint paint=new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
//绘制
canvas.drawCircle(150,150,50,paint);
//绘制结束,释放
surfaceHolder.unlockCanvasAndPost(canvas);
}
//修改时调用
public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
//销毁时调用
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
}
});
为解决SurfaceView无法使用View的基本视图方法的问题,Android在4.0之后引入了纹理视图TextureView。
tag: SurfaceView、SurfaceHolder、预览