0

我正在写游戏。当用户结束关卡时,会发生以下情况:

  1. 发送 POST,检查关卡记录是否被打破。(1-5 秒)
  2. 如果是这样,请显示Dialog“输入您的姓名”。(快速地)
  3. 当用户单击确定时,发送一个带有他的记录的 POST。(1-5 秒)

当用户结束关卡时,他处于GameActivity. checkWorldRecord()被调用,并在其中AsyncTask启动 an:

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正在做这三件事,我在一开始就列出了:

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,而不是整体ActivityshowEnterNameAndSend()。但是,showDialogOnUiThread()(由 调用showEnterNameAndSend())需要Activity,以显示DialogUI 线程,使用activity.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

我想到的两个解决方案:

第一个是创建一个活动(我们称之为 SpecialActivity)。

这个活动将持有一个广播接收器,它将在 onResume 中注册,并将在 onPause 中取消注册。

您的每一个活动都将继承 SpecialActivity 并从 doInBackground 方法获得广播,然后调用该方法显示对话框。

第二个是创建一个 INVISIBLE 活动(我们称之为 DialogActivity),它的唯一职责是在 onCreate 中调用对话框,并在对话框被解除后杀死自己。该活动也将从 doInBackground (startActivity...) 触发。

也许有更简单和智能的解决方案,但这就是我的想法:D

于 2012-10-04T20:48:17.110 回答
0

尝试将对话框上的上下文更改为应用程序上下文而不是活动上下文。您可以通过使用包含对应用程序上下文的静态引用的自定义应用程序类(我的偏好)或使用 GameActivity.this.getAppContext() 来获取它

于 2012-10-04T20:54:57.343 回答