SurfaceView是View的继承结构中一个比较特殊的子类,它的作用是提供一个第二线程来完成图形的绘制。因此应用程序不需要等待View的图形绘制,第二线程会异步完成图形的绘制。
SurfaceView实现的步骤:
- 继续SurfaceView并实现SurfaceHolder.Callback接口,该接口提供了SurfaceView创建、属性发生变化、销毁的时间点,那么你可以在适当的时间点完成具体的工作。
- 在SurfaceView初始化的时候调用SurfaceView.getHolder()方法获取一个SurfaceHolder,SurfaceHolder用于管理SurfaceView的工作过程。为了让SurfaceHolder起作用,必须为SurfaceHolder添加回调方法(即第一步实现的SurfaceHolder.Callback):
- SurfaceHolder.addCallBack(SurfaceHolder.Callback);
- 在SurfaceView内创建第二线程的内部类(暂命名为SecondThread),它的主要任务是完成Canvas的图形绘制。为了能让SecondThread获得Canvas实例,必须给SecondThread传递在步骤二中获得的SurfaceHolder。现在就可以通过SurfaceHolder.lockCanvas()方法得到Canvas实例,并在Canvas上绘制图形。当图形绘制完成后,必须马上调用SurfaceHolder.unlockCanvasAndPost()为Canvas解锁,使其他线程可以使用该画布。
有几个注意点:
- 每一次通过SurfaceHolder获取的Canvas都会保持上一次绘制的状态。如果需要重新绘制图形,可以通过调用Canvas.drawColor()或Canvas.drawBitmap()来擦除上次遗留的图形。
- 并不一定只用第二线程来绘制图形,也可以开启第三,第四个线程来绘制图形。
- 注意线程安全。
- 不需要像View一样,调用invalidate()方法来指示图形的刷新。
SurfaceView的一个范例:
- package com.sin90lzc.android.sample;
-
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
-
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
-
- public class CanvasView extends SurfaceView implements SurfaceHolder.Callback {
-
- public static class Point {
- private float x;
- private float y;
-
- public Point(float x, float y) {
- this.x = x;
- this.y = y;
- }
-
- public float getX() {
- return x;
- }
-
- public void setX(float x) {
- this.x = x;
- }
-
- public float getY() {
- return y;
- }
-
- public void setY(float y) {
- this.y = y;
- }
-
- public Point nextPoint(Orien o) {
- float tempX = x;
- float tempY = y;
- switch (o) {
- case UP:
- tempY = y - LINE_LENGTH;
- break;
- case DOWN:
- tempY = y + LINE_LENGTH;
- break;
- case LEFT:
- tempX = x - LINE_LENGTH;
- break;
- case RIGHT:
- tempX = x + LINE_LENGTH;
- break;
- case UNKNOWN:
- break;
- }
- return new Point(tempX, tempY);
- }
- }
-
- enum Orien {
- UP, LEFT, DOWN, RIGHT, UNKNOWN
- }
-
- public static class DrawThread extends Thread {
-
- private List<Point> points = Collections
- .synchronizedList(new ArrayList<Point>());
- private boolean mRun;
-
- private Paint mPaint;
- private Orien curOrien;
-
- public synchronized void setRun(boolean run) {
- this.mRun = run;
- notifyAll();
- }
-
- public synchronized boolean getRun() {
- while (!mRun) {
- try {
- wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- return mRun;
- }
-
-
- private synchronized boolean doKeyDown(int KeyCode, KeyEvent event) {
- synchronized (holder) {
- Point p = null;
- switch (KeyCode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- if (curOrien != Orien.DOWN) {
- curOrien = Orien.UP;
- p = curPoint.nextPoint(curOrien);
- }
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (curOrien != Orien.UP) {
- curOrien = Orien.DOWN;
- p = curPoint.nextPoint(curOrien);
- }
- break;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (curOrien != Orien.RIGHT) {
- curOrien = Orien.LEFT;
- p = curPoint.nextPoint(curOrien);
- }
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (curOrien != Orien.LEFT) {
- curOrien = Orien.RIGHT;
- p = curPoint.nextPoint(curOrien);
- }
- break;
- default:
- curOrien = Orien.UNKNOWN;
- }
- if (p != null) {
- curPoint = p;
- points.add(p);
- setRun(true);
- }
- Log.i(LOG_TAG, curOrien.toString());
- }
- return true;
- }
-
-
- private synchronized boolean doKeyUp(int KeyCode, KeyEvent event) {
- synchronized (holder) {
- setRun(false);
- curOrien = Orien.UNKNOWN;
- }
- return true;
- }
-
- SurfaceHolder holder;
- private Point curPoint;
-
- public DrawThread(SurfaceHolder holder) {
- this.holder = holder;
- mPaint = new Paint();
- mPaint.setColor(Color.GREEN);
- curPoint = new Point(50, 50);
- points.add(curPoint);
- }
-
- public void resetPoint() {
- }
-
- private void doDraw(Canvas canvas) {
- for (int i = 0; i + 1 < points.size(); i += 1) {
- Point lp = points.get(i);
- Point np = points.get(i + 1);
- canvas.drawLine(lp.getX(), lp.getY(), np.getX(), np.getY(),
- mPaint);
- }
- }
-
- @Override
- public void run() {
- Canvas canvas = null;
- while (getRun()) {
- try {
- canvas = holder.lockCanvas();
- synchronized (holder) {
- doDraw(canvas);
- }
- } finally {
- holder.unlockCanvasAndPost(canvas);
- setRun(false);
- }
- }
- }
- }
-
- private DrawThread thread;
- public static final String LOG_TAG = "CanvasView";
- private static final int LINE_LENGTH = 30;
-
- public CanvasView(Context context) {
- super(context);
-
- }
-
- public CanvasView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
-
- SurfaceHolder holder = getHolder();
- holder.addCallback(this);
- thread = new DrawThread(holder);
- thread.start();
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- return thread.doKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return thread.doKeyUp(keyCode, event);
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- Log.i(LOG_TAG, "surfaceChanged");
- thread.resetPoint();
- thread.setRun(true);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.i(LOG_TAG, "surfaceCreated");
- thread.resetPoint();
- thread.setRun(true);
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.i(LOG_TAG, "surfaceDestroyed");
- thread.setRun(false);
- }
-
- }