开发者

Surfaceview flickering

I have a problem with the flickering. Here is my code.

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.joi开发者_Go百科n();
                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);
                }
            }
        }
    }
}

}

The drawn image flickers. It looks like the bitmap that is drawn at one point is drawn on one surface and not the other so it looks like flickering, the bitmap that is drawn when we touch action_up is done, that is a solid image and does not flickers. Could someone please help me with this one. Thanks


When you are drawing in the Canvas of a SurfaceView, you must always draw every pixel of the surface.
Here you are not always clearing the Canvas in onDraw(), hence the flickering.


One thing you could do to mitigate that (and to kinda contradict Guillaume :)) is to use surfaceholder.lockCanvas(rectangle), where it is only the specified rectangle part of the canvas which is then drawn (but you must draw every pixel of that rect). Here it is, ripped from the LunarLandar sample:

@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);
                }
            }
        }
    }


I didn't read through all of your code, but I think this article will help.

The essence of the article is that flickering is due to double buffering and can be eliminated by drawing not to the argument Canvas but to a bitmap used as the canvas and then drawing that bitmap to the 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

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜