开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜