Surface
查询Android SKD得到解释(Handle onto a raw buffer that is being managed by the screen compositor.)
处理由屏幕合成程序管理的原始缓冲区。
Android中的Surface就是一个用来画图形(graphics)或图像(image)的地方,对于View及其子类,都是画在Surface上,各Surface对象通过Surfaceflinger合成到frameBuffer,每个Surface都是双缓冲,它有一个backBuffer和一个frontBuffer,Surface中创建了Canvas对象,用来管理Surface绘图操作,Canvas对应Bitmap,存储Surface中的内容。流程为:
1:创建一个Bitmap对象。
2:创建一个Canvas对象关联创建的Bitmap对象。
3:在Canvas上进行绘制。
4:锁定Canvas画布。
5:将Bitmap内容绘制到backBuffer中去。
6:解锁Canvas画布。
SurfaceView
在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面,由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行行绘制,又由于不占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输入得不到及时响应。
SurfaceView的绘制方式效率非常高,因为SurfaceView的窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何一个子元素或者是局部的刷新都会导致整个视图结构全部重绘一次,因此效率非常低下)。
可以理解为Surface就是管理数据的地方,SurfaceView就是展示数据的地方。
SurfaceHolder
通过SurfaceHolder这个接口去访问Surface,而执行getHolder()方法可以得到SurfaceHolder接口。当SurfaceView的窗口可见时,Surface就会被创建,当SurfaceView窗口隐藏时,Surface就会被销毁。
SurfaceView提供了一个运行在渲染线程的surface,若要更新屏幕,需要了解以下线程知识。
- 所有SurfaceView 和 SurfaceHolder.Callback的方法都应该在主线程(UI线程)里面调用,应该要确保渲染进程所访问变量的同步性。
- 必须确保只有当Surface有效的时候,(也就是当Surface的生命周期在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()之间)才能让渲染进程访问。
SurfaceView与Surface的联系就是,Surface是管理显示内容的数据(implementsParcelable),包括存储于数据的交换。而SurfaceView就是把这些数据显示出来到屏幕上面。
SurfaceHolder是控制surface的一个抽象接口,你可以通过SurfaceHolder来控制surface的尺寸和格式,或者修改surface的像素,监视surface的变化等等,SurfaceHolder是SurfaceView的典型接口。
与直接控制SurfaceView来修改surface不同,使用SurfaceHolder来修改surface时,需要注意lockCanvas() 和Callback.surfaceCreated().这两个方法。
通过SurfaceHolder这个接口去访问Surface,而执行getHolder()方法可以得到SurfaceHolder接口。当SurfaceView的窗口可见时,Surface就会被创建,当SurfaceView窗口隐藏时,Surface就会被销毁。
SurfaceHolder控制surface的流程所使用的几个方法。
Demo:
package com.example.zhangyadong.test.study;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static final String TAG = MySurfaceView.class.getSimpleName();
private Canvas mCanvas;
private SurfaceHolder mSurfaceHolder;
private boolean mIsDrawing;
private Path mPath;
private Paint mPaint;
/**
* 每30帧刷新一次屏幕
**/
public static final int TIME_IN_FRAME = 300;
public MySurfaceView(Context context) {
super(context);
initView();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
mPath = new Path();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(10);
mPaint.setStyle(Paint.Style.STROKE);
setFocusable(true);
setFocusableInTouchMode(true);
setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsDrawing = true;
new Thread(this).start();
//在surface创建时被调用
Log.e(TAG, "surfaceCreated");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//在surface改变时被调用
Log.e(TAG, "surfaceChanged");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
//在surface销毁时被调用
Log.e(TAG, "surfaceDestroyed");
}
@Override
public void run() {
while (mIsDrawing) {
long startTime = System.currentTimeMillis();
synchronized (mSurfaceHolder) {
draw();
}
/**取得更新结束的时间**/
long endTime = System.currentTimeMillis();
/**计算出一次更新的毫秒数**/
int diffTime = (int) (endTime - startTime);
/**确保每次更新时间为300帧**/
while (diffTime <= TIME_IN_FRAME) {
diffTime = (int) (System.currentTimeMillis() - startTime);
/**线程等待**/
Thread.yield();
}
}
}
private void draw() {
try {
mCanvas = mSurfaceHolder.lockCanvas();//锁定画布,获取Canvas对象进行绘制
float x = (int) (1 + Math.random() * (mCanvas.getWidth()));
float y = (int) (1 + Math.random() * (mCanvas.getHeight()));
mPath.lineTo(x, y);
mCanvas.drawPath(mPath, mPaint);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mCanvas != null) {
mSurfaceHolder.unlockCanvasAndPost(mCanvas);//解除锁定,提交画布内容
}
}
}
}