0

私はゲームを書いています。ユーザーがレベルを終了すると、次のことが起こります。

  1. POSTを送信して、レベルレコードが破られたかどうかを確認します。(1-5秒)
  2. その場合は、Dialog「名前を入力してください」と表示します。(速い)
  3. ユーザーが[OK]をクリックしたら、自分のレコードとともにPOSTを送信します。(1-5秒)

ユーザーがレベルを終了すると、彼はになりGameActivityます。checkWorldRecord()が呼び出され、その中で、AsyncTaskが開始されます。

private void checkWorldRecord(final RecordType recordType, final double time, final int level)
{
    new Handler(Looper.getMainLooper()).post(new Runnable()
    {
        @Override
        public void run()
        {
            new DownloadTask(recordType, time, level).execute();
        }
    });
}

DownloadTask私が最初にリストしたこれらの3つのことをしています:

class DownloadTask extends AsyncTask<Void, Void, Void>
{
    RecordType recordType;
    double time;
    int level;

    public DownloadTask(RecordType recordType, double time, int level)
    {
        super();
        this.recordType = recordType;
        this.time = time;
        this.level = level;
    }

    @Override
    protected Void doInBackground(Void... params)
    {
        try
        {
            if (!Network.isWorldRecord(recordType, time, level)) // 1.
            {
                return null;
            }
        }
        catch (Exception e)
        {
            return null;
        }
        Dialogs.showEnterNameAndSend(GameActivity.this, recordType, time, level, highScores.getGamesPlayed(),
                highScores.getStars()); // 2.
        return null;
    }
}

ユーザーがゲームの後に待つとき、彼がにとどまっているなら、すべてがうまくいきますGameActivity

問題は、次の場合です。

  1. ユーザーがゲームを終了しました。checkWorldRecord()と呼ばれます。
  2. 別のスレッドで、最初のPOSTが開始されます。
  3. ユーザーが戻るボタンを押して、アクティビティを別のアクティビティに変更しMainActivityます。
  4. AsyncTaskチェックを終えて、新記録があります。showEnterNameAndSend()最初にビルドして後で表示したいAlertDialog。ブーム。私たちが通過していたのでGameActivity、そして今MainActivityが一番上にあります:

public static void showEnterNameAndSend(final Activity activity, final RecordType recordType, final double time,
        final int level, final long gamesPlayed, final int stars)
{
    AlertDialog.Builder builder = new AlertDialog.Builder(activity); // BOOM!!!
    final EditText editText = new EditText(activity);
    editText.setFilters(new InputFilter[]
    { new InputFilter.LengthFilter(Const.MAX_NAME_LENGTH) });
    editText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
    builder.setView(editText);
    builder.setTitle(recordType + " world record!");
    builder.setMessage("Enter your name:");
    builder.setPositiveButton("Ok", new DialogInterface.OnClickListener()
    {
        @Override
        public void onClick(DialogInterface dialog, int whichButton)
        {
            String username = editText.getText().toString();
            if (username.equals(""))
            {
                return;
            }

            try
            {
                Network.sendRecord(recordType, username, time, level, gamesPlayed, stars); // 3.
            }
            catch (Exception e)
            {
                showInternetError(activity);
            }
        }
    });
    showDialogOnUiThread(activity, builder);
}

private static void showDialogOnUiThread(Activity activity, final AlertDialog.Builder builder)
{
    activity.runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            builder.show();
        }
    });
}

はい、Context全体ではなく、Activityを渡すことも好みshowEnterNameAndSend()ます。ただし、showDialogOnUiThread()(によって呼び出されるshowEnterNameAndSend())は、 UIスレッドにActivityを表示するために、を必要とします。Dialogactivity.runOnUiThread()

これを修復する方法は?たぶん、例えば、いくつかの方法があるので、私は、すでに隠されている可能性があるgetCurrentActivity()を渡す必要はありませんか?Activityどういうわけかダイアログの表示をキャンセルできれば、ユーザーが閉じた後GameActivityも問題ありません。

4

3 に答える 3

1

そのダイアログを表示しようとしてアプリのクラッシュを防ぎたい場合は、フラグを設定することでそれを解決できます。

public static boolean userIsOut = false;

次に、ユーザーがそのアクティビティを終了したときにtrueに設定します。

@Override
protected void onDestroy() {
    userIsOut = true;
    super.onDestroy();
}

ShowEnterNameAndSend()メソッドでは、次のように実行できます。

if(!userIsOut)
    showDialogOnUiThread(activity, builder);

したがって、ユーザーがそのアクティビティに参加していない場合、ダイアログは作成されません。

しかし、ダイアログを表示することを主張する場合は、独自のgetCurrentActivity()メソッドを作成する必要があると思います。それを達成するために、あなたはその変数を保持するクラスを持つことができます

public static class ActivityHolder {
     public static Activity current;

     public static void setCurrentActivity(Activity act) {
           current = act;
     }

     public static Activity getCurrentActivity() {
           return current;
     }
}

また、この現在のアクティビティをすべてのアクティビティのonResumeメソッドとonCreateメソッドに設定する必要があります...これにより、現在のアクティビティが常にわかり、そのアクティビティを使用してダイアログを表示できます。

@Override
protected void onResume() {
    ActivityHolder.setCurrentActivity(this);
    super.onResume();
}
于 2012-10-05T09:45:24.300 に答える
0

私が頭に浮かんだ2つの解決策:

1つ目は、アクティビティを作成することです(これをSpecialActivityと呼びます)。

このアクティビティは、onResumeに登録され、onPauseに登録解除されるブロードキャストレシーバーを保持します。

各アクティビティはSpecialActivityを継承し、doInBackgroundメソッドからブロードキャストされてから、ダイアログを表示するためのメソッドを呼び出します。

2つ目は、inVISIBLEアクティビティ(DialogActivityと呼びます)を作成することです。その唯一の責任は、onCreateでダイアログを呼び出し、ダイアログが閉じられたら自分自身を強制終了することです。そのアクティビティは、doInBackground(startActivity ...)からもトリガーされます。

もっとシンプルでスマートな解決策があるかもしれませんが、それが私の頭に浮かんだことです:D

于 2012-10-04T20:48:17.110 に答える
0

ダイアログのコンテキストを、アクティビティコンテキストではなくアプリケーションコンテキストに変更してみてください。アプリケーションコンテキストへの静的参照を保持するカスタムアプリケーションクラス(私の好み)を使用するか、GameActivity.this.getAppContext()を使用して取得できます。

于 2012-10-04T20:54:57.343 に答える