surfaceview的问题

时间:2011-04-14 11:57:40

标签: android clear surfaceview flicker

我有一个闪烁的问题。 这是我的代码。

public class Tutorial2D3 extends Activity {

Panel panel;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    panel = new Panel(this);
    setContentView(panel);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(1, 1, 1, "Clean Canvas");
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    panel.cleanCanvas();
    return true;
}

class Panel extends SurfaceView implements SurfaceHolder.Callback {
    TutorialThread thread;
    Bitmap icon;
    int iconWidth;
    int iconHeight;
    int touchX;
    int touchY;
    int mCount = 0;

    public Panel(Context context) {
        super(context);
        icon = BitmapFactory
                .decodeResource(getResources(), R.drawable.icon);
        iconWidth = icon.getWidth();
        iconHeight = icon.getHeight();
        getHolder().addCallback(this);
        thread = new TutorialThread(getHolder(), this);
        setFocusable(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int x = touchX - (iconWidth / 2);
        int y = touchY - (iconHeight / 2);
        if(mCount>0) {
            canvas.drawColor(Color.BLACK);
            mCount--;
        }
        canvas.drawBitmap(icon, (x > 0 ? x : 0), (y > 0 ? y : 0), null);    
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        thread.setRunning(false);
        do {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } while (retry);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchX = (int) event.getX();
            touchY = (int) event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            touchX = (int) event.getX();
            touchY = (int) event.getY();
            break;
        case MotionEvent.ACTION_UP:
            break;
        default:
            break;
        }
        return true;
    }

    private void cleanCanvas() {
        mCount = 2;
    }
}



class TutorialThread extends Thread {
    private SurfaceHolder _surfaceHolder;
    private Panel _panel;
    private boolean _run = false;

    public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
        _surfaceHolder = surfaceHolder;
        _panel = panel;
    }

    public void setRunning(boolean run) {
        _run = run;
    }

    @Override
    public void run() {
        Canvas c;
        while (_run) {
            c = null;
            try {
                c = _surfaceHolder.lockCanvas(null);
                synchronized (_surfaceHolder) {
                    _panel.onDraw(c);
                }
            } finally {
                if (c != null) {
                    _surfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}

}

绘制的图像闪烁。 看起来在一个点上绘制的位图在一个表面上绘制而不是在另一个表面上绘制,因此它看起来像闪烁,当我们触摸action_up时绘制的位图,这是一个实体图像并且不会闪烁。有人可以请帮我这个。 感谢

3 个答案:

答案 0 :(得分:1)

当您在SurfaceView的画布中绘图时,您必须始终绘制表面的每个像素
在这里,您并不总是清除onDraw()中的画布,因此会闪烁。

答案 1 :(得分:1)

你可以做的一件事就是减轻它(并且与Guillaume相矛盾:))是使用surfaceholder.lockCanvas(矩形),它只是画布的指定矩形部分,然后绘制(但你必须绘制)那个矩形的每个像素)。在这里,从LunarLandar样本中删除:

@Override
    public void run() {
        while (mRun) {
            Canvas c = null;
            try {
                c = mSurfaceHolder.lockCanvas(Rectangle);
                synchronized (mSurfaceHolder) {
                    if (mMode == STATE_RUNNING) updatePhysics();
                    doDraw(c);
                }
            } finally {
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }

答案 2 :(得分:1)

我没有通读所有代码,但我认为this article会有所帮助。

本文的实质是闪烁是由于双缓冲,可以通过绘制不是参数Canvas而是绘制到用作画布的位图然后将该位图绘制到arg Canvas来消除:

int myCanvas_w, myCanvas_h;
Bitmap myCanvasBitmap = null;
Canvas myCanvas = null;
Matrix identityMatrix;

@Override
public void surfaceCreated(SurfaceHolder holder) {

myCanvas_w = getWidth();
myCanvas_h = getHeight();
myCanvasBitmap = Bitmap.createBitmap(myCanvas_w, myCanvas_h, Bitmap.Config.ARGB_8888);
myCanvas = new Canvas();
myCanvas.setBitmap(myCanvasBitmap);

identityMatrix = new Matrix();
}

@Override
protected void onDraw(Canvas canvas) {

paint.setStyle(Paint.Style.STROKE);
 paint.setStrokeWidth(3);

 //int w = myCanvas.getWidth();
 //int h = myCanvas.getHeight();
 int x = random.nextInt(myCanvas_w-1);
 int y = random.nextInt(myCanvas_h-1);
 int r = random.nextInt(255);
 int g = random.nextInt(255);
 int b = random.nextInt(255);

 paint.setColor(0xff000000 + (r << 16) + (g << 8) + b);
 myCanvas.drawPoint(x, y, paint); // <--------- Here's where you draw on your bitmap

 canvas.drawBitmap(myCanvasBitmap, identityMatrix, null);
 // ^---------- And here's where you draw that bitmap to the canvas

}