android提供了view进行绘图处理,View可以满足大部分的绘图需求。View通过刷新来重绘视图,android通过VSYNC信号来进行屏幕的重绘,刷新的时间为16ms,如果在16ms内完成了绘图的操作,用户将不会感到卡顿现象,如果执行的逻辑过多,特别是在需要不断的重绘界面时,就会发生阻塞主线程的现象。从而导致卡顿现象,这种情况,我们自定的view的Log中经常会看到如下的警告。
“Skipped 47 frames! The application may be doing to much work on its main thread”
这些警告是因为在绘制的过程中,处理的逻辑太多导致的。
View主要适用于主动更新的情况下,而SurfaceView主要适用与被动的更新,列如频繁的刷新。
View在主线程中对画面进行刷新,而SurfaceView通常会在子线程进行页面的刷新。
View在绘图的时候没有使用双缓冲机制,而SurfaceView在底层实现机制中就已经实现了双缓冲机制。
总结一句话,如果你的自定义的View需要频繁的刷新,或者刷新的数据量比较大的时候,就可以考虑使用SurfaceView代替View。
SurfaceView的使用
SurfaceView的使用虽然比View复杂,但是SurfaceView在使用时,有一套使用的模板代码,大部分的绘图操作都可以使用这个模板代码来使用。
package xiaoxu.picture;
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.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Created by Administrator on 2016/4/3.
*/
public class MySufView extends SurfaceView implements Runnable,SurfaceHolder.Callback {
private SurfaceHolder holder;
private Boolean mIsDrawing;//子线程标志位。
private Canvas mCanvas; //用于绘图的canvas
private Path mPath;
public MySufView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
//View的创建
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsDrawing = true;
new Thread(this).start();
}
private void initView() {
holder = getHolder();//对SurfaceHolder进行初始化
holder.addCallback(this);//并注册一个SurfaceHolder的回调方法
setFocusable(true);
setFocusableInTouchMode(true);
setKeepScreenOn(true);
mPath = new Path();
}
//View改变
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
//View销毁
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
}
@Override
public void run() {
long start = System.currentTimeMillis();
while (mIsDrawing){
draw1();
}
long end = System.currentTimeMillis();
if(end - start < 100){
try {
Thread.sleep(100-(end - start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void draw1() {
try {
Paint paint = new Paint();
mCanvas = holder.lockCanvas(); //获取当前的canvas对象,需要注意的是,我们获取的仍然是上次的canvas对象,如果需要
//之前的图都将保留,如果需要擦除,可以在绘制之前,调用canvas.color()来执行清屏
mCanvas.drawColor(Color.WHITE);
if(mPath != null){
mCanvas.drawPath(mPath,paint);
}
}catch (Exception e){
}finally {
holder.unlockCanvasAndPost(mCanvas);//最后要将画布内容提交,要将这个方法放入到final中,保证内容每次都可以提交。
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mPath.moveTo(event.getX(),event.getY());
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(event.getX(),event.getY());
break;
}
return true;
}
}
详细如下
http://blog.csdn.net/luoshengyang/article/details/8661317/