众所周知,view是通过刷新来重绘视图的,Android系统通过发出VSYNC信号来进行屏幕重绘,刷新的时间间隔为16ms,如果在16ms内view完成你所需要的所有操作,那么用户在视觉上就不会产生卡顿的感觉;而如果执行的操作逻辑太多,特别是需要频繁刷新的界面,就会不断阻塞主线程,从而导致画面卡顿。
因此Android提供了surfaceView。
1.View主要适用于主动更新的情况,surfaceView主要适用于被动更新,例如频繁的刷新。
2.View在主线程 中对View进行刷新,surfaceView通常会用一个子线程来进行页面的刷新。
3.View在绘图时没有双缓冲机制,而surfaceView在底层就已经实现了双缓冲机制。
因此如果自定义view需要频繁刷新或者刷新时候的数据处理量比较大,那么就可以考虑使用surfaceView来代替View
使用SurfaceeView有一套模板,以下用一个例子说明:用surfaceView做出示波器的效果,画出正弦波。
package com.example.tangzh.MyView;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;import com.example.tangzh.mylearn.R;/*** Created by TangZH on 2017/4/30.*/ public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable //继承并实现两个接口 {private SurfaceHolder mHolder;//用于绘图的Canvasprivate Canvas mCanvas;//子线程标志位private boolean mIsDrawing;//画笔private Paint mPaint;private Path mPath;//x坐标private int x=0;//y坐标private int y=400;public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr){super(context, attrs, defStyleAttr);initView();}public MySurfaceView(Context context){super(context);initView();}public MySurfaceView(Context context, AttributeSet attrs){super(context, attrs);initView();}private void initView(){mHolder=getHolder();mHolder.addCallback(this);setFocusable(true);setFocusableInTouchMode(true);this.setKeepScreenOn(true);}@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {mIsDrawing=true;mPath=new Path();mPath.moveTo(0,400);mPaint=new Paint();mPaint.setColor(getResources().getColor(R.color.colorTheme));mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(5);new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {}@Overridepublic void surfaceDestroyed(SurfaceHolder surfaceHolder) {mIsDrawing=false;}@Overridepublic void run() {while (mIsDrawing){draw();x+=5;y=(int)(100* Math.sin(x*2*Math.PI/180)+400);mPath.lineTo(x,y);}}private void draw() {try {mCanvas=mHolder.lockCanvas();//SurfaceView背景 mCanvas.drawColor(Color.WHITE);mCanvas.drawPath(mPath,mPaint);}catch (Exception e){e.printStackTrace();}finally {if(mCanvas!=null)mHolder.unlockCanvasAndPost(mCanvas); //对画布内容进行提交 }} }
要注意,通过SurfaceView对象的lockCanvas()方法,就可以获取当前的Canvas绘图对象,这个对象跟上次的Canvas对象是同一个,因此之前的绘图操作都会被保留,如果需要擦出,则可以在绘制前,通过drawColor()方法来进行清屏操作。