我正在为Android编写一款小游戏。游戏使用Thread在SurfaceView上绘制。在Thread的run()方法中,我测试游戏是否结束,如果是,我尝试在对话框上显示游戏,但这给了我前面提到的错误信息。 我知道当非UI线程试图弄乱UI时会发生此错误。我想知道的是显示这种对话的最佳方法。我已粘贴下面的代码。 谢谢你的帮助:
public class BouncingBallActivity extends Activity{
private static final int DIALOG_GAMEOVER_ID = 0;
private BouncingBallView bouncingBallView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bouncingBallView = new BouncingBallView(this);
bouncingBallView.resume();
setContentView(bouncingBallView);
}
protected Dialog onCreateDialog(int id)
{
switch (id) {
case DIALOG_GAMEOVER_ID:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Game Over.")
.setCancelable(false)
.setPositiveButton("Try Again",
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface arg0,
int arg1)
{
bouncingBallView.resume();
}
})
.setNegativeButton("Exit",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which)
{
BouncingBallActivity.this.finish();
}
});
AlertDialog gameOverDialog = builder.create();
return gameOverDialog;
default:
return null;
}
}
class BouncingBallView extends SurfaceView implements Runnable
{
SurfaceHolder surfaceViewHolder;
Canvas canvas;
Context context;
Thread drawingThread;
boolean drawingThreadIsRunning;
boolean isInitialised;
Ball ball;
ArtificialIntelligence ai;
BouncingBallView(Context context)
{
//
}
public void pause()
{
isInitialised = false;
drawingThreadIsRunning = false;
boolean joiningWasSuccessful = false;
while(!joiningWasSuccessful)
try {
drawingThread.join();
joiningWasSuccessful = true;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void resume()
{
isInitialised = false;
drawingThread = new Thread(this);
drawingThread.setName("Drawing Thread");
drawingThreadIsRunning = true;
drawingThread.start();
}
public void run()
{
while(drawingThreadIsRunning)
{
if(!surfaceViewHolder.getSurface().isValid())
continue;
if(gameOver())
BouncingBallActivity.this.showDialog(DIALOG_GAMEOVER_ID);
try{
canvas = surfaceViewHolder.lockCanvas();
if(!isInitialised)init(canvas);
update();
surfaceViewHolder.unlockCanvasAndPost(canvas);
}catch(Exception e)
{
Log.e(BouncingBallActivity.this.toString(),String.format("%s: Just as the emperor had foreseen!\n(This error is expected. Canvas destroyed while animations continue.)", e.toString()));
}
}
}
private void init(Canvas canvas)
{
ball = new Ball(canvas, Color.GREEN);
ai = new ArtificialIntelligence(canvas, (int) (ball.getX()+100),canvas.getWidth());
isInitialised = true;
}
}
}
答案 0 :(得分:2)
尝试这样......你不能从主线程以外的地方对ui进行任何更改..在 if(gameOver())
之后,在你的线程中输入这个部分//if(gameOver())
runOnUiThread(new Runnable() {
@Override
public void run() {
BouncingBallActivity.this.showDialog(DIALOG_GAMEOVER_ID);
}
});
答案 1 :(得分:1)
您正在从worker(后台)线程调用Dialog。你需要从主线程调用它。尝试使用Activity.runOnUIThread()调用它并在其中创建一个处理程序,它将调用你的showDialog方法。
答案 2 :(得分:0)
我用[https://stackoverflow.com/a/16886486/3077964]来解决问题。
在runOnUiThread()中显示对话框后,您需要暂停BouncingBallView的线程。 那就是:
//if(gameOver()){
BouncingBallActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() { BouncingBallActivity.this.showDialog(DIALOG_GAMEOVER_ID); } }); pause(); }
答案 3 :(得分:0)
对我来说,我在surfaceView中使用了这个处理程序来创建dialogBox。
Handler someHandler = new Handler(){
//this method will handle the calls from other threads.
public void handleMessage(Message msg) {
final Dialog dialog = new Dialog(Game.this);
dialog.setContentView(R.layout.question_dialog);
dialog.setTitle("GAME OVER");
Button restart=(Button)dialog.findViewById(R.id.btn Restart);
// Set On ClickListener
restart.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(Game.this, "Restart Game", Toast.LENGTH_LONG).show();
dialog.dismiss();
}
}
});
dialog.show();
}
所以,我在游戏线程中编写了looper.prepared()来调用这个Handler。如果播放器功率= 0,则会出现此对话框。
Looper.prepare();
//create the message for the handler
Message status = someHandler.obtainMessage();
Bundle data = new Bundle();
String msgContent = null;
data.putString("SOMETHING", msgContent);
status.setData(data);
someHandler.sendMessage(status);
Looper.loop();
}