Android SurfaceView 当锁定画布不为 null 时显示空白
我正在创建一个简单的游戏,使用扩展 SurfaceView 的视图并使用线程在 SurfaceView 上绘制图像。游戏将有自己的线程(游戏引擎)来绘制和更新可绘制对象。
我有 3 个类来实现这一点,即 BattleActivity、BattleView 和 BattleThread。 BattleActivity 是从另一个活动调用的。 BattleThread 将调用 BattleView.update() 和 BattleView.render() 来完成这项工作。但我没有看到任何工作。我知道这一切都可以通过日志记录和调试(我已经尝试过)来实现,但我仍然无法弄清楚哪个是不正确的。有人愿意帮助我吗?
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);
}}
战斗视图:
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();
}}
战斗线程:
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
}
}
}
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
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我知道这是一篇旧帖子,但以防万一它可以帮助那里的人。
我遇到了同样的问题,与您的代码几乎相同,并且发现我需要做的就是从我的重写的 onDraw(Canvas canvas) 方法中调用 postInvalidate() 方法表面视图。
这是我的代码:
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 overriddenonDraw(Canvas canvas)
method in my SurfaceView.This is my code:
您需要调用 onDraw(Canvas canvas) 来渲染而不是 render(),因为 onDraw 使用硬件屏幕缓冲区。检查第二个示例 如何使用画布内的动画框架?
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?