Dialogs/AlertDialogs:如何在对话框启动时"阻止执行"(.NET风格)

Ted*_*Ted 69 android

来自.NET环境我现在正在寻找了解Dialog如何在Android中运行的方法.

在.NET中,调用MessageBox.Show(...)创建并显示弹出对话框.在对Show的调用中,我可以指定弹出窗口中应该有哪些按钮,例如:

DialogResult myDialogResult = MessageBox.Show("My text here", "My caption here", MessageBoxButtons.YesNoCancel);
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,当在弹出窗口中按下按钮时,对Show的调用将返回一个DialogResult,通知我单击了哪个按钮.请注意,在.NET中,执行将在调用Show(...)的行中停止,因此它可以在按下按钮时返回值.

如果我在上面的例子中按"否",则myDialogResult将等于

myDialogResult == DialogResult.No
Run Code Online (Sandbox Code Playgroud)

由于我发现使用/创建弹出窗口的.NET方式非常简单直观,我想在Android中创建弹出窗口的方式.

所以,问题是,是否有人知道如何"停止执行",如MessageBox.Show,然后每按一次按钮返回一个值(对话框消失)?

问候


编辑1: 更清楚一点:

我需要执行停止并等到用户选择了一个按钮来单击弹出窗口.显示对话框的调用后面的代码取决于在对话框中单击的按钮.

这就是为什么我不能使用Erich和Alex所建议的,因为在下面建议的onClick方法中编写代码是行不通的.原因是我无法继续"正常执行".让我举一个例子:

让我举一个例子:

int nextStep = 0; // this variable will not be reached from within the onClick-methods

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Hello!")
       .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                nextStep = 1; // *** COMPILER ERROR!! ***
            }
        })
        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                nextStep = 2; // *** COMPILER ERROR!! ***
            }
        })
        .create().show();

if (nextStep == 1)
{
    // then do some damage
}
else if (nextStep == 2
    // dont do damage
Run Code Online (Sandbox Code Playgroud)

如果我希望执行依赖于弹出窗口中的选择,我会以某种方式使onClick方法中的"正常执行"(在本例中为nextStep)中的所有变量都可用,这对我来说听起来很糟糕.

编辑2:

另一个明显的例子是弹出窗口,询问"你想继续"选项"是""否".

如果用户按"是",则应中止整个方法,否则应继续执行.你怎么解决这个问题呢?

问候

Rom*_*Guy 47

Ted,你不想这样做,真的:)最大的原因是如果你在显示一个Dialog时阻止UI线程,你将阻止负责绘制和处理Dialog事件的线程.这意味着您的对话框将无响应.如果用户单击对话框需要几秒钟,您还将导致ANR.

Erich的答案正是您所需要的.我知道这不是你想要的,但这并不重要.我们设计了Android以防止开发人员编写同步对话框,因此您没有太多选择.

  • 不要告诉别人他们不应该尝试做他们想做的事情.如果有什么"可怕和懒惰",那(答案)就是这样.当然你可以在Android中制作模态对话框,你只需要编写更多代码.从用户的角度来看,用户界面没什么不好.许多UI框架,而不仅仅是Windows,都支持这一概念.如果有一个简单的单行答案,海报可能不需要提问.如果你不想做回答他的问题的工作,那就别管它了. (56认同)
  • 请注意,OP当然不希望实际停止UI _thread_,只是想阻止用户_workflow_.由于这是一个有效且常见的用例(因为用户几乎不会与他们的小工具执行多个_parallel_交互,并且系统通常需要_wait_为他们),所以很自然地期望一些简单的模态对话API无缝匹配"单线程用户"现实.如果做起来不容易,这是可以理解的.但是,如果Android团队能够提出一个聪明的方法来使其像问题中所示的那样微不足道,它只能帮助我们所有人.谢谢! (32认同)
  • 这是一团糟,因为您正在以一种不适合Android的方式构建您的代码.只是做*不同*.如果你拒绝这样做,那就是你的问题.例如,不是使用3个阻塞对话框(顺便说一句,我觉得这是一个糟糕而懒惰的用户界面),为什么你没有一个Activity会出现所有问题,只有当用户验证你开始做任何你的应用程序时应该做的.你问了一个问题,我们已经回答了,到目前为止,你唯一能说的就是你不喜欢我们的答案.对不起,但他们不会改变. (20认同)
  • @rml我在Android框架团队工作,我们专门设计了框架,没有阻止当前执行线程的模态对话框.我知道它是如何完成的,但它不是我们为Android选择的模型. (8认同)
  • @radhoo由于这样的小细节,我之所以看到这么多可怕的移动应用程序(iOS应用程序看起来像是由Java人员和由C++人设计的Android异常)(例如).你必须学习和理解你正在使用的平台,不一定用你自己的想法强迫你的方式.每个平台都有自己的优点和缺点,无论喜欢与否.Android中的生命周期模型就是这样设计的,处理它并学习围绕它的架构. (6认同)
  • 我不得不同意这是一个常见的场景,这就是为什么它受到包括.NET在内的几个框架的支持.Android没有为此提供简单直接的实现是没有意义的.现在我必须打破我的代码的逻辑流程,以适应Android的复杂的做事方式. (4认同)
  • Nate,看了我的回答.我解释为什么这不是一个好主意. (2认同)
  • @Romain其他框架也不会阻塞主线程.这是一种方便的方法. (2认同)

Eri*_*ass 19

在Android中,结构与.NET不同:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Hello!")
       .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // Handle Ok
           }
       })
       .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // Handle Cancel
           }
       })
       .create();
Run Code Online (Sandbox Code Playgroud)

将为您提供一个带有两个按钮的对话框,您可以使用回调来处理按钮单击.您可能能够编写一些代码来使语法更接近.NET,但是对话框生命周期非常紧密Activity,因此最终可能比它的价值更麻烦.其他对话框引用在这里.

  • 那么在Android中没有"模态"对话框这样的东西?你不能认真. (4认同)

Min*_*ker 19

Daniel上面的答案的简化版本.此函数在警告对话框中从用户获得"是"或"否",但可以轻松修改以获取其他输入.

private boolean mResult;
public boolean getYesNoWithExecutionStop(String title, String message, Context context) {
    // make a handler that throws a runtime exception when a message is received
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message mesg) {
            throw new RuntimeException();
        } 
    };

    // make a text input dialog and show it
    AlertDialog.Builder alert = new AlertDialog.Builder(context);
    alert.setTitle(title);
    alert.setMessage(message);
    alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            mResult = true;
            handler.sendMessage(handler.obtainMessage());
        }
    });
    alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            mResult = false;
            handler.sendMessage(handler.obtainMessage());
        }
    });
    alert.show();

    // loop till a runtime exception is triggered.
    try { Looper.loop(); }
    catch(RuntimeException e2) {}

    return mResult;
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*ebb 11

在Android中,Dialogs是异步的,因此您将不得不以不同的方式构建代码.

所以在C#中你的逻辑在伪代码中运行了类似的东西:

void doSomeStuff() {
    int result = showDialog("Pick Yes or No");

    if (result == YES) {
        //do stuff for yes
    }
    else if (result == NO) {
        //do stuff for no
    }

    //finish off here
}
Run Code Online (Sandbox Code Playgroud)

对于Android来说,它必须不那么整洁.想想就好.你会有OnClickListener这样的:

public void onClick(DialogInterface dialog, int whichButton) {
   if (whichButton == BUTTON_POSITIVE) {
      doOptionYes();
   }
   else if (whichButton == BUTTON_NEGATIVE) {
      doOptionNo();
   }
}
Run Code Online (Sandbox Code Playgroud)

然后由以下方法支持:

void doOptionYes() {
    //do stuff for yes
    endThings();
}

void doOptionNo() {
    //do stuff for no
    endThings();
}

void endThings() {
    //clean up here
}
Run Code Online (Sandbox Code Playgroud)

那么一种方法现在是四种.它可能看起来不是很整洁,但我担心它的工作方式.

  • 我觉得这有点令人沮丧,因为如果一切正常,我的执行流程会绕过对话框.如果有问题,我会问"继续"或"忘记".所以现在我有2种方法来获取持续的代码.所以我必须把它放在自己的方法中.所以我必须重做所有重新进入对话框的设置.糟糕的设计恕我直言 (3认同)

Dan*_*iel 8

PasswordDialog dlg = new PasswordDialog(this);

if(dlg.showDialog() == DialogResult.OK)

{

    //blabla, anything your self

}


public class PasswordDialog extends Dialog
{
    int dialogResult;
    Handler mHandler ;

    public PasswordDialog(Activity context, String mailName, boolean retry)
    {

        super(context);
        setOwnerActivity(context);
        onCreate();
        TextView promptLbl = (TextView) findViewById(R.id.promptLbl);
        promptLbl.setText("Input password/n" + mailName);
    }
    public int getDialogResult()
    {
        return dialogResult;
    }
    public void setDialogResult(int dialogResult)
    {
        this.dialogResult = dialogResult;
    }
    /** Called when the activity is first created. */

    public void onCreate() {
        setContentView(R.layout.password_dialog);
        findViewById(R.id.cancelBtn).setOnClickListener(new android.view.View.OnClickListener() {

            @Override
            public void onClick(View paramView)
            {
                endDialog(DialogResult.CANCEL);
            }
            });
        findViewById(R.id.okBtn).setOnClickListener(new android.view.View.OnClickListener() {

            @Override
            public void onClick(View paramView)
            {
                endDialog(DialogResult.OK);
            }
            });
        }

    public void endDialog(int result)
    {
        dismiss();
        setDialogResult(result);
        Message m = mHandler.obtainMessage();
        mHandler.sendMessage(m);
    }

    public int showDialog()
    {
        mHandler = new Handler() {
            @Override
              public void handleMessage(Message mesg) {
                  // process incoming messages here
                //super.handleMessage(msg);
                throw new RuntimeException();
              }
          };
        super.show();
        try {
            Looper.getMainLooper().loop();
        }
        catch(RuntimeException e2)
        {
        }
        return dialogResult;
    }

}
Run Code Online (Sandbox Code Playgroud)


fup*_*uck 5

在Android中尝试优化内存和性能对话框是异步的(它们也因此而受到管理).来自Windows世界,您习惯于模态对话框.Android对话框是模态的,但在执行时更像非模态.显示对话框后,执行不会停止.

我见过的Android中Dialogs的最佳描述是在"Pro Android"中http://www.apress.com/book/view/1430215968

这不是一个完美的解释,但它可以帮助您围绕Windows和Android中的Dialogs之间的差异.在Windows中你想做A,用对话框问一个问题,然后做B或C.在android设计中,你需要在OnClickListener的onClick()中为B和C所需的所有代码用于对话框.然后执行A并启动对话框.你完成了A!当用户点击按钮时,B或C将被执行.

Windows
-------
A code
launch dialog
user picks B or C
B or C code
done!

Android
-------
OnClick for B code (does not get executed yet)
OnClick for C code (does not get executed yet)
A code
launch dialog
done!
user picks B or C
Run Code Online (Sandbox Code Playgroud)

  • 如果有很多类似的问题要依次回答,并且每个选择都会影响以后的过程,那么使用android中使用的不间断对话框会很麻烦,但是使用Windows对话框会容易得多。绝对不是一样。 (2认同)

art*_*926 5

Android和iOS的开发人员认为他们是强大而聪明的,足以拒绝Modal Dialog概念(这已经在市场上存在很多年了,之前并没有打扰过任何人),不幸的是我们.我相信有解决Android的 - 因为你可以使用Runnable接口类显示来自非UI线程对话,应该有一种方法在该线程(非UI)要等到对话结束.

编辑:这是我的解决方案,效果很好:

    int pressedButtonID;
    private final Semaphore dialogSemaphore = new Semaphore(0, true);
    final Runnable mMyDialog = new Runnable()
    {
        public void run()
        {
            AlertDialog errorDialog = new AlertDialog.Builder( [your activity object here] ).create();
            errorDialog.setMessage("My dialog!");
            errorDialog.setButton("My Button1", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    pressedButtonID = MY_BUTTON_ID1;
                    dialogSemaphore.release();
                    }
                });
            errorDialog.setButton2("My Button2", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    pressedButtonID = MY_BUTTON_ID2;
                    dialogSemaphore.release();
                    }
                });
            errorDialog.setCancelable(false);
            errorDialog.show();
        }
    };

    public int ShowMyModalDialog()  //should be called from non-UI thread
    {
        pressedButtonID = MY_BUTTON_INVALID_ID;
        runOnUiThread(mMyDialog);
        try
        {
            dialogSemaphore.acquire();
        }
        catch (InterruptedException e)
        {
        }
        return pressedButtonID;
    }
Run Code Online (Sandbox Code Playgroud)