SurfaceView与View的区别
如果在16ms内View完成了你所需要执行的所有操作,那么用户在视觉上,就不会产生卡顿的感觉;而如果操作的逻辑太多,特别是需要频繁刷新的界面商行,那么慢就不会不断阻塞主线程,从而导致画面卡顿。为了避免这一问题的产生,Android系统提供了SurfaceView组价来解决这个问题,SurfaceView可以说是View的孪生兄弟,但它与View还是有所不同的,它们的区别主要变现在以下几点。
- View 主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新,例如频繁刷新。
- View 在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面的刷新。
- View 在绘图时没有使用缓冲机制,而SurfaceView的底层实现机制中就已经实现了双缓冲机制。
SurfaceView的使用
1.创建SurfaceView
创建自定义的SurfaceView继承自SurfaceView,并实现两个接口——SurfaceHolder
.Callback和Runnable,并重写相关的方法。其中SurfaceHolder.Callback的三个方法分别对应SurfaceView的创建,改变和销毁的过程。
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable {
public MySurfaceView(Context context) {
super(context);
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
@Override
public void run() {
}
}
2.初始化SurfaceView
在自定义SurfaceView的构造方法中,需要对SurfaceView进行初始化。在自定义的SurfaceView中,通常需要定义以下三个成员变量:
private SurfaceHolder mHolder;
//画布,用于画图
private Canvas mCanvas;
//子线程标志位
private boolean mIsDrawing;
初始化方法就是对SurfaceHolder进行初始化,通过以下代码来初始化一个SurfaceView对象,并注册SurfaceViewHolder的回调方法。
mHolder=getHolder();
mHolder.addCallback(this);
另外两个成员变量——Canvas和标志位。对Canvas我们已经非常熟悉了,与在View的onDraw()方法中使用Canvas绘图一样,在SurfaceView中,我们也使用Canvas进行绘图,另一个标志位,则是用来控制子线程,SurfaceView通常会挂起一个子线程来进行绘制,而这个标志位就是可以控制子线程。
3.使用SurfaceView
通过SurfaceHolder对象的lockCanvas()方法,就可以获得当前的Canvas绘图对象。接下来,就可以在View中进行的绘制操作一下进行绘制了。不过需要注意的是,在获取到的Canvas对象还是继续上次的Canvas对象,而不是一个新的对象。因此,之前的绘图操作都是将保留,如果需要擦除,则可以在绘制前,通过drawColor()方法进行清屏的操作。
绘制的时候,充分利用SurfaceView的三个回调方法,在surfaceCreate()方法中个开启子线程进行绘制,而子线程使用一个while(mIsDrawing)的循环来不停地进行绘制,在绘制的具体逻辑中,通过lockCanvas()方法获得的Canvas对象进行绘制,并通过unlockCanvasAndPost(mCanvas)方法对画布内容进行提交。
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable {
private SurfaceHolder mHolder;
//画布,用于画图
private Canvas mCanvas;
//子线程标志位
private boolean mIsDrawing;
public MySurfaceView(Context context) {
this(context,null);
}
public MySurfaceView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr,0);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
intView();
}
private void intView() {
mHolder=getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
}
@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){
draw();
}
}
private void draw() {
try {
mCanvas=mHolder.lockCanvas();
//进行绘制
}catch (Exception e){
}finally {
if (mCanvas!=null){
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}
以上的代码基本上可以满足大部分的SurfaceView绘制需求,唯一需要注意的是在绘制方法中,将mHolder.unlockCanvasAndPost(mCavas)方法放到finally代码中,来保证每次都能将内容提交。
网友评论