How can I show a dialog from my rendering thread?
I have a problem with my game here. I kind of don't understand how Android handles the dialog. When I call the dialog from an activity, like this, it works:
public class RocketActivity extends GameActivity implements onGameFinishedListener {
private final int MENU = 0;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some codes here
setContentView(layout);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
//case KeyEvent.KEYCODE_BACK:
//return true;
case KeyEvent.KEYCODE_MENU:
showDialog(MENU);
break;
default:
break;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected Dialog onCreateDialog(int id) {
return new AlertDialog.Builder(RocketActivity.this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(com.fugo.Rocket.R.string.dialog_pause_title)
.setPositiveButton(string.dialog_button_reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
RocketActivity.this.rocketView.init();
}
})
.setNegativeButton(string.dialog_button_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).create();
}
}
There, the code works perfectly and the dialog shows up in front. But then I tried to show the dialog from a drawing thread (my intention is to call gameFinished()
after some condition) the dialog didn't show.
GameThread.java
package com.fugo.Rocket.Engine;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class GameThread extends Thread {
private SurfaceHolder surfaceHolder;
private GameView gameView;
private boolean run;
public GameThread(SurfaceHolder surfaceHolder, GameView gameView) {
this.surfaceHolder = surfaceHolder;
this.gameView = gameView;
}
public SurfaceHolder getSurfaceHolder() {
return surfaceHolder;
}
public GameView getGameView() {
return gameView;
}
public void setRunning(boolean run) {
this.run = run;
}
@Override
public void run() {
Canvas c;
Log.d(TAG, "starting game loop");
while(run) {
c = null;
try {
c = this.surfaceHolder.lockCanvas(null);
synchronized(surfaceHolder) {
this.gameView.Update(FRAME_PERIOD);
//render state to the screen
//draws the canvas on the panel
this.gameView.onDraw(c);
}
}
catch (Exception e) {
}
finally {
//in case on an exception the surface is not left in
//an inconsistent state
if(c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
GameView.java
package com.fugo.Rocket.Engine;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.fugo.Rocket.Engine.EventListener.onGameFinishedListener;
public abstract class GameView extends SurfaceView implements SurfaceHolder.Callback{
List<onGameFinishedListener> listeners;
public GameThread gameThread;
protected int width;
protected int height;
public GameView(Context context) {
super(context);
width = 320;
height = 480;
listeners = new ArrayList<onGameFinishedListener>();
}
public abstract void init();
public void registerGameFinishedListener(onGameFinishedListener listener) {
listeners.add(listener);
}
protected void GameFinished(GameView gameView) {
for (onGameFinishedListener listener : listeners) {
synchronized(gameThread.getSurfaceHolder()) {
listener.onGameFinished(gameView);
}
}
}
public void Update(float gameTime) {
if(finished)
{
GameFinished(this);
}
}
@Override
protected void onDraw(Canvas canvas) {
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
this.width = w;
this.height = h;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
startThread();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopThread();
}
public void startThread() {
gameThread.setRunning(true);
gameThread.start();
}
public void stopThread() {
boolean retry = true;
gameThread.setRunning(false);
while(retry) {
try {
gameThread.join();
retry = false;
}
catch(InterruptedException e) {
}
}
}
}
I have an onGameFinishedListener
interface which is, as you see above, implemented by the activity.
package com.fugo.Rocket.Engine.EventListener;
import com.fugo.Rocket.Engine.GameView;
public interface onGameFinishedListener {
public void onGameFinished(GameView gameView);
}
package com.fugo.Rocket.Activities;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.RelativeLayout;
import com.fugo.Rocket.RocketView;
import com.fugo.Rocket.Engine.GameActivity;
import com.fugo.Rocket.Engine.GameView;
import com.fugo.Rocket.Engine.EventListener.onGameFinishedListener;
import com.fugo.Rocket.R.string;
public class RocketActivity extends GameActivity implements onGameFinishedListener {
@Override
public void onGameFinished(GameView gameView) {
showDialog(END);
//startActivity(new Intent(this, StartMenuActivity.class));
}
}
So then when the game is finished, it's supposed to show the dialog. But in the end it won't show up. I tried to analyze this problem and I thought the problem is the dialog is being called through the gameThread.
GameThread > update > gameFinish > show dialog
Anyone have a solution or a better way to implement this game finish eve开发者_StackOverflow社区nt?
All UI work must be doing from the UI thread. You cannot show a dialog from a non UI thread. You can use runOnUiThread to make that part run on the right thread.
精彩评论