如何实现Android SurfaceView

来源:互联网 发布:富士康机器人编程软件 编辑:程序博客网 时间:2024/05/19 10:12

SurfaceView是View的继承结构中一个比较特殊的子类,它的作用是提供一个第二线程来完成图形的绘制。因此应用程序不需要等待View的图形绘制,第二线程会异步完成图形的绘制。

SurfaceView实现的步骤:

  1. 继续SurfaceView并实现SurfaceHolder.Callback接口,该接口提供了SurfaceView创建、属性发生变化、销毁的时间点,那么你可以在适当的时间点完成具体的工作。
  2. 在SurfaceView初始化的时候调用SurfaceView.getHolder()方法获取一个SurfaceHolder,SurfaceHolder用于管理SurfaceView的工作过程。为了让SurfaceHolder起作用,必须为SurfaceHolder添加回调方法(即第一步实现的SurfaceHolder.Callback):
    SurfaceHolder.addCallBack(SurfaceHolder.Callback);

  3. 在SurfaceView内创建第二线程的内部类(暂命名为SecondThread),它的主要任务是完成Canvas的图形绘制。为了能让SecondThread获得Canvas实例,必须给SecondThread传递在步骤二中获得的SurfaceHolder。现在就可以通过SurfaceHolder.lockCanvas()方法得到Canvas实例,并在Canvas上绘制图形。当图形绘制完成后,必须马上调用SurfaceHolder.unlockCanvasAndPost()为Canvas解锁,使其他线程可以使用该画布。

有几个注意点:

  1. 每一次通过SurfaceHolder获取的Canvas都会保持上一次绘制的状态。如果需要重新绘制图形,可以通过调用Canvas.drawColor()或Canvas.drawBitmap()来擦除上次遗留的图形。
  2. 并不一定只用第二线程来绘制图形,也可以开启第三,第四个线程来绘制图形。
  3. 注意线程安全。
  4. 不需要像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);}}@Overridepublic 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);//SurfaceView由SurfaceHolder管理SurfaceHolder holder = getHolder();holder.addCallback(this);thread = new DrawThread(holder);thread.start();}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {return thread.doKeyDown(keyCode, event);}@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event) {return thread.doKeyUp(keyCode, event);}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {Log.i(LOG_TAG, "surfaceChanged");thread.resetPoint();thread.setRun(true);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {Log.i(LOG_TAG, "surfaceCreated");thread.resetPoint();thread.setRun(true);}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.i(LOG_TAG, "surfaceDestroyed");thread.setRun(false);}}

Notice:例子中,没一次按下方向键都得把所有坐标重新绘制一遍。如果只是绘制最后一次没绘制的点时,不知道为什么会变成虚线,有待解决。

原创粉丝点击