Dialog
“输入您的姓名”。 (快)当用户结束等级时,他在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
。
问题是:
checkWorldRecord()
被称为。{/ li>
MainActivity
。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()
调用)需要Activity
,以Dialog
在UI线程上显示activity.runOnUiThread()
。
如何修复此问题?例如,有一些方法getCurrentActivity()
,所以我不必传递一个Activity
,它已经被隐藏了?如果我能以某种方式取消显示对话框,在用户关闭GameActivity
后,它也会没问题。
答案 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()