Android SurfaceView displays blank when locked canvas is not null

匿名 (未验证) 提交于 2019-12-03 01:40:02

问题:

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     } } 

}

回答1:

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


回答2:

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?



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!