SurfaceView与View区别
前面我们所有的讲解基本都是自定义View来实现各种Android的自定义控件,但编写过相机的Android程序员,肯定对SurfaceView不陌生,那什么时候该用SurfaceView呢?
我们先来看一个概念,在Android中屏幕的刷新时间为16ms,如果View能够在16ms内完成所有的执行的绘图操作,那么在视觉上,界面是流畅的;否则APP就会卡顿,我们经常会看到如果View的逻辑非常复杂,Android Studio都会提示以下日志:
Skipped 60 frames! The application maybe doing too much work on its main thread
之所以会提示这个警告,是因为我们在自定义View的绘图操作中,执行了非常复杂的逻辑运算,导致16s内并没有完成绘制,所以当出现在自定义View中非常复杂的耗时的逻辑运算时,就需要使用SurfaceView。
SurfaceView在两个方面改进了View的绘图操作:
1.使用了双缓冲技术
2.自带画布,支持在子线程中更新画布内容
这里说的双缓冲技术,就是多加了一块缓冲画布,当需要执行绘图操作的时候,先在缓冲画布上绘制,绘制好后直接将缓冲画布的内部更新到主画布之中。这样,在屏幕更新的时候,只需要把缓冲画布上的内容照搬过来就可以了,就不会存在耗时的逻辑问题,也解决了超时绘制。
使用缓冲的Canvas绘图
前面我们已经介绍了,SurfaceView时自带画布的,具有双缓冲技术,那么问题来了,我们怎么才能拿到这块画布呢?直接先上代码:
SurfaceHolder surfaceHolder=getHolder();
Canvas canvas=surfaceHodler.lockCanvas();
//中间执行绘图操作
surfaceHolder.unlockCanvasAndPost(canvas);
我们这里直接通过surfaceHolder.lockCanvas()获取到了缓冲画布,并且将画布上锁,防止被其他线程篡改,当绘图完成之后释放锁,通过surfaceHolder.unlockCanvasAndPost(canvas)进行释放,这段代码不仅释放锁,还将缓冲画布的内容更新到主线程的画布上,从而显示到屏幕中。
这里上锁是防止其他线程同时更新缓冲画布,造成缓冲画布乱七八糟,所以我们需要加锁,至于什么是线程锁,死锁,释放锁等知识,这是Java多线程的知识,详情参考Java多线程书籍或者操作系统,这属于基础,篇幅有限,这里就不赘述了。
SurfaceView生命周期
在讲解SurfaceView生命周期之前,我们先要理解三个概念:Surface,SurfaceView,SurfaceHolder。有过MVC开发经验的小伙伴应该会非常熟悉,SurfaceView就是视图V,Surface中保存了缓冲画布和绘制内容相关的各种数据,也就是模型M,SurfaceHolder很明显就是MVC中的C控制器。
所以,当我们需要操作SurfaceView的时候,必然需要Surface存在,所以Android专门提供了监听Surface生命周期的函数:
public class DemoSurfaceView extends SurfaceView {
private SurfaceHolder surfaceHolder;
public DemoSurfaceView(Context context) {
super(context);
}
public DemoSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
this.surfaceHolder=getHolder();
this.surfaceHolder.addCallback(new SurfaceHolder.Callback() {