在当前活动中显示对话框

时间:2012-10-04 20:31:01

标签: android multithreading user-interface android-activity android-asynctask

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

  1. 发送一个帖子,检查等级记录是否被打败。 (1-5秒)
  2. 如果是,请显示Dialog“输入您的姓名”。 (快)
  3. 当用户单击“确定”时,发送包含其记录的POST。 (1-5秒)
  4. 当用户结束等级时,他在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正在做这三件事,我在开头就列出了这些:

    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()被称为。{/ li>
    2. 在单独的线程中,第一个POST开始。
    3. 用户按下后退按钮并将活动更改为另一个,MainActivity
    4. AsyncTask完成检查,我们有新记录。 showEnterNameAndSend()想要先构建并稍后显示AlertDialog。繁荣。因为我们传递了GameActivity,现在MainActivity位于顶部:

    5. 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()调用)需要Activity,以Dialog在UI线程上显示activity.runOnUiThread()

      如何修复此问题?例如,有一些方法getCurrentActivity(),所以我不必传递一个Activity,它已经被隐藏了?如果我能以某种方式取消显示对话框,在用户关闭GameActivity后,它也会没问题。

3 个答案:

答案 0 :(得分: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();
}

答案 1 :(得分:0)

我想到了两个解决方案:

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

此活动将保留将在onResume中注册的广播接收器,并将在onPause中取消注册。

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

第二,是创建一个INVISIBLE活动(让我们称之为DialogActivity) 它唯一的责任是在onCreate中调用对话框,并在一旦它自杀 对话已被驳回。 该活动也将从doInBackground(startActivity ...)触发。

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

答案 2 :(得分:0)

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