Android-SurfaceView的总结
缘由:
Android系统提供View进行绘图处理,但是很多时候会显得心有余而力不足,比如当view绘图进行大量的操作,容易使主线程阻塞,并且在logcat输出···
"skipped 47 frames! the application may be doing much work in main thread"
这个当我在页面进行大量的视图动画时,经常出现。
所以当你的View需要频繁的刷新,或者刷新时数据处理量比较大时,建议使用SurfaceView。
View绘图方式:
View是通过刷新来更新视图。系统通过发送VSYnc信号来通知屏幕进行刷新,刷新频率为16ms,因此当你的View刷新时间超过16ms,就会出现卡顿。
View和surfaceView的比较:
1.view适用于主动进行画面更新,而surfaceView适合被动进行更新。
2.view更新运行在主线程,容易造成主线程的阻塞,而surfaceView运行在新的子线程中。
3.VIew绘图没有使用双缓冲机制,而surfaceView底层已经实现双缓冲机制。
说明:双缓冲机制--当要在指定View上绘制图形时,不直接在View上绘制,而是先绘制到内存中的Bitmap图片上,等到缓存的Bitmap 绘制好,以后,再将bitmap上的直接绘制View组件上。
surfaceView的使用:
1.继承自SurfaceView,实现SurfaceHolder,CallBack,Runnable接口
2.并且重写抽象方法
2.在xml文件中使用或者动态生成
实例代码:
public class KillView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private SurfaceHolder holder;
private Canvas canvas;
private boolean isDrawing;
private Paint paint;
public KillView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public KillView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public KillView(Context context) {
super(context);
init();
}
public void init(){
Log.e("TAG","init");
holder=getHolder();
holder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
}
Path path;
@Override
public void run() {
long start=System.currentTimeMillis();
while (isDrawing){
draw();
}
long end=System.currentTimeMillis();
Log.e("TAG","start="+start+" end="+end);
if(end-start<100){
try{
Thread.sleep(100-end+start);
}catch (Exception e){
e.printStackTrace();
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e("TAG","create");
isDrawing=true;
path=new Path();
paint=new Paint();
paint.setColor(getResources().getColor(R.color.colorAccent));
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e("TAG","change");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e("TAG","destroy");
isDrawing=false;
}
public void draw(){
try{
canvas=holder.lockCanvas();
canvas.drawCircle(getWidth()/2,getWidth()/2,100,paint);
holder.unlockCanvasAndPost(canvas);
canvas=holder.lockCanvas();
canvas.drawColor(Color.WHITE);
//canvas.drawPath(path,paint);
canvas.drawArc(0,0,100,100,0,360,true,paint);
}catch (Exception e){
throw new IllegalArgumentException();
}finally{
if(holder!=null){
holder.unlockCanvasAndPost(canvas);
}
}
}
}
代码中方法说明:
1.getHolder()
surfaceView 一般与surfaceHolder结合使用,surfaceHolder用于向关联的View绘图 ,可通过getHolder方法获得当前View的holder。
2.lockCanvas()
锁定surfaceView对象,获取surfaceView上的Canvas对象。
3.unlockCanvasANdPost()
当调用该方法时,之前绘制的内容还在内存中,当下次lockCanvas()时,可能会覆盖之前的内容,因此如果想要持久化绘制内容,添加以下代码:
holder.lockcanvas(new Rect(0,0,0,0);
holder.unlockcanvasAndPost(canvas);