SurfaceView
View通过刷新来重绘视图,Android系统通过发出VSYNC信号来进行屏幕重绘,刷新的间隔为16ms。如果在16ms内View完成了你所需要执行的所有操作。那么用户在视觉上就不会产生卡顿的感觉;而如果执行的操作逻辑太多,特别是需要频繁的刷新界面上,例如游戏界面, 那么就会不断的阻塞主线程,从而导致画面卡段。
Skipped 47 frames!The Application may be doing too much work on its main thread
这个警告的产生,很多情况下就是因为在绘制过程中,处理太多逻辑造成的。
所以SurfaceView就产生了。
SurfaceView继承自View,已知的直接子类有GLSurfaceView和VideoView,都是需要频繁刷新的View
区别:
- View主要用于主动更新的情况,SurfaceView主要用于被动更新,比如频繁的刷新操作
- View在主线程中对画面进行刷新,而SurfaceView通过一个子线程进行页面的刷新
- View没有双缓冲机制,而SurfaceView在底层实现机制中已经实现双缓冲机制
双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。
如果你的自定义View需要频繁的刷新,或者刷新时数据处理量较大,就可以使用SurfaceView来取代View
使用SurfaceView绘制正弦曲线:
code:
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;
/**
* Created by feathers on 16-11-18.
*/
public class SurfaceViewDemo extends SurfaceView implements SurfaceHolder.Callback,Runnable{
// SurfaceHolder
private SurfaceHolder mHolder;
// 用于绘图的Canvas
private Canvas mCanvas;
//子线程标志位
private boolean mIsDrawing;
private int x = 0;
private int y = 0;
private Path mPath;
private Paint mPaint;
public SurfaceViewDemo(Context context) {
this(context, null);
}
public SurfaceViewDemo(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SurfaceViewDemo(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
// 初始化SurfaceHolder,并注册SurfaceHolder的回调方法
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
// mHolder.setFormat(PixelFormat.OPAQUE);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(10);
}
// SurfaceView创建
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
// 被创建后启动一个新的线程用来绘制
mIsDrawing = true;
new Thread(this).start();
}
// SurfaceView改变
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
}
// SurfaceView销毁
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
// 销毁后,子线程结束
mIsDrawing = false;
}
@Override
public void run() {
while (mIsDrawing) {
draw();
x += 1;
y = (int) (100 * Math.sin(x * 2 * Math.PI / 180) + 400);
mPath.lineTo(x, y);
}
}
private void draw() {
try {
// 获取Canvas
mCanvas = mHolder.lockCanvas();
// SurfaceView背景
mCanvas.drawColor(Color.WHITE);
mCanvas.drawPath(mPath, mPaint);
} catch (Exception e) {
}finally {
if (mCanvas != null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.mCanvas = canvas;
}
}