Android SurfaceView displays blank when locked can

2019-09-11 17:32发布

I'm creating a simple game using a view which extends a SurfaceView and using a thread to draw images on the SurfaceView. The game will have its own thread (game engine) to draw and update drawables.

I have 3 classes to achieve this, namely BattleActivity, BattleView, and BattleThread. The BattleActivity is called from another activity. BattleThread will call BattleView.update() and BattleView.render() to do the job. But I don't see anything working. I know it all is reachable through logging and debugging (which I have tried), but I still can't figure out which is incorrect. Anyone care to help me?


public class BattleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    // Making it full screen
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    //... shortened

    // Create the battle view
    battleView = new BattleView(this);
    battleView.setBackground(battleBackground);
    setContentView(battleView);
}}

The BattleView:

public class BattleView  extends SurfaceView implements SurfaceHolder.Callback{
//... shortened

public BattleView(Context context) 
{
    super(context);
    getHolder().addCallback(this);
    // Surface has been created
    battleThread = new BattleThread(getHolder(), this); 
    setFocusable(true);
}

public synchronized void render(Canvas canvas) 
{
    // this function is called when I do debugging, but no image is shown
    // canvas and background is not null
    canvas.drawBitmap(background, 0, 0, null);
}

public synchronized void update()
{
    monsterState = leftMonster.update();
    //... shortened
    rightMonster.update();
}

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

The BattleThread:

public class BattleThread extends Thread {
public BattleThread(SurfaceHolder surfaceHolder, BattleView battleView)
{
    super();
    this.surfaceHolder = surfaceHolder;
    this.battleView = battleView;
}

@Override
public void run() 
{
    Canvas canvas;
    //... shortened

    while (running) 
    {
        canvas = null;
        // try locking the canvas for exclusive pixel editing
        // in the surface
        try 
        {
            canvas = this.surfaceHolder.lockCanvas();
            synchronized (surfaceHolder) 
            {
                beginTime = System.currentTimeMillis();
                framesSkipped = 0;  // resetting the frames skipped
                // update game state 
                this.battleView.update();

                beginTime = System.currentTimeMillis();
                // render it
                this.battleView.render(canvas);             

                //... shortened
            }
        }
        finally 
        {
            if (canvas != null) 
            {
                surfaceHolder.unlockCanvasAndPost(canvas);
            }
        }   // end finally
    }
}

}

2条回答
走好不送
2楼-- · 2019-09-11 17:46

I know this is an old post but just in case it helps someone out there.

I had this same problem, almost identical code to yours, and found that all I needed to do was call postInvalidate() from my overridden onDraw(Canvas canvas) method in my SurfaceView.

This is my code:

@Override
protected void onDraw(Canvas canvas)
{
   mPaperPlaneImage.draw(canvas);
   postInvalidate();
}
查看更多
我想做一个坏孩纸
3楼-- · 2019-09-11 17:48

You need to call onDraw(Canvas canvas) to render instead of your render() because onDraw works with hardware screen buffers. Check the second example How can I use the animation framework inside the canvas?

查看更多
登录 后发表回答