Android确认对话框返回true或false

12

似乎没有一种简单的方法可以使警告对话框返回一个简单的值。
这段代码无法工作answer变量无法从监听器内部设置,实际上它甚至无法编译)

public static boolean Confirm(Context context) {
    boolean answer;
    AlertDialog dialog = new AlertDialog.Builder(context).create();
    dialog.setTitle("Confirmation");
    dialog.setMessage("Choose Yes or No");
    dialog.setCancelable(false);
    dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int buttonId) {
            answer = true;
        }
    });
    dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "No", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int buttonId) {
            answer = false;
        }
    });
    dialog.setIcon(android.R.drawable.ic_dialog_alert);
    dialog.show();
    return answer;
}

注意:这个方法很重要的一点是它应该是自包含的,即它不依赖于外部变量或构造。只需要调用它并得到你的答案,真或假。

那么,该怎么办呢?这个简单的希望返回truefalse 的愿望似乎比它应该有的更加复杂。

此外,setButton方法的形式为:

dialog.setButton(int buttonId, String buttonText, Message msg)

但是不清楚如何使用它,消息发送到哪里,发给谁,使用哪个处理程序?

8个回答

18

我曾在这个论坛上发过类似的问题,但最终我得到了答案。 我在那篇帖子中的问题是如何创建一个单独的确认对话框类,其他类或活动可以访问它,因此使用该确认对话框类时我们不需要编写冗长的代码。

这里是我的答案。

首先,您必须创建DialogHandler.java文件。

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import src.app.R;

public class DialogHandler {
    public Runnable ans_true = null;
    public Runnable ans_false = null;

    // Dialog. --------------------------------------------------------------

    public boolean Confirm(Activity act, String Title, String ConfirmText,
            String CancelBtn, String OkBtn, Runnable aProcedure, Runnable bProcedure) {
        ans_true = aProcedure;
        ans_false= bProcedure;
        AlertDialog dialog = new AlertDialog.Builder(act).create();
        dialog.setTitle(Title);
        dialog.setMessage(ConfirmText);
        dialog.setCancelable(false);
        dialog.setButton(DialogInterface.BUTTON_POSITIVE, OkBtn,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int buttonId) {
                         ans_true.run();
                    }
                });
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, CancelBtn,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int buttonId) {
                        ans_false.run();
                    }
                });
        dialog.setIcon(android.R.drawable.ic_dialog_alert);
        dialog.show();
        return true;
    }
}

这是在另一个类中调用它的示例

public class YourActivity extends Activity {
    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(myclick);
    }

    public final Button.OnClickListener myclick = new Button.OnClickListener() {
        @Override
        public void onClick(View v) {
            doclick();
        }
    };

    public void doclick() {
        DialogHandler appdialog = new DialogHandler();
        appdialog.Confirm(this, "Message title", "Message content",
                "Cancel", "OK", aproc(), bproc());
    }

    public Runnable aproc(){
        return new Runnable() {
            public void run() {
                Log.d("Test", "This from A proc");
            }
          };
    }

    public Runnable bproc(){
        return new Runnable() {
            public void run() {
                Log.d("Test", "This from B proc");
            }
          };
    }


}

@Lion789,请看我在自己的答案中对你评论的回复。真正的测试在于:在调用doClick()后,在onClick()方法中放置一些代码以检查用户对DialogHandler对话框的响应,并查看该代码执行是否等待对话框关闭。我认为不会。 - ilomambo
2
我喜欢你的方法,它正在运行。我已经检查过了。 - Zar E Ahmer
1
@Roro 做得好。它有效。这应该是被接受的答案。 - denizen
1
@AsepRoro 很好的逻辑..执行得很顺利。这确实应该是被接受的答案。 - Neil B

10

其实,我很高兴自己找到了一个简单的答案,但事实上,尽管我找到了一种返回值的方法(如下所示),它并没有什么用处

实际问题是,我想要一个同步的Dialog,在 dialog.show() 后等待用户回答后才恢复您的代码执行。在Android中没有这样的东西。所有的对话框都是异步的,所以 dialog.show() 只是将对话框发布到某个队列中(我想)并继续执行。因此,您无法及时获得答案。

为了证明我的价值(虽然不值钱),下面有如何在构建对话框的方法中设置一个值。也许还有其他与对话框生命周期无关的用途。




为了提供一些相关信息,我会说如果您替换:

boolean answer;

使用

final boolean answer;

在监听器内部可以访问该变量,但无法给它赋新值,因为它被声明为final

这里有一个技巧。
将变量定义为:

final boolean[] answer = new boolean[1];

有些人已经看出为什么这会起作用了。这里的最终变量不是布尔数组的单个元素,而是数组本身。
所以现在你可以按照自己的意愿分配数组元素[0]。

dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int buttonId) {
        answer[0] = true;
    }
});
. . .
return answer[0];

最后,您可以从您的方法中返回它。


你有找到更好的解决方案吗? - Lion789
1
@Lion789 正如我所说,这并不是一个真正的解决方案,我已经解释了为什么在当前的Android操作系统中无法找到解决方案。简而言之,我没有找到更好的解决方案。根据Android的建议,您应该将代码放在对话框的onClick()监听器中。这是在关闭对话框后执行它的唯一方法。 - ilomambo
iLomambo,你试过使用调用Runnable的顶部那个吗? - Lion789
我已经转移到其他项目,所以我没有尝试过它。但是,如果你理解我的答案,那么它的行为方式就很明显了。由于Android的异步特性,当你调用show()时,对话框会被显示并且代码会继续执行,它不会等待用户点击OK - ilomambo
如果代码中除了例如onClick(dialog(proca(), procb())之外没有其他内容,那么屏幕只会在选择后更改,而不管异步操作,因为在procA中我告诉它要做什么,除非在对话框中被告知运行,否则不会执行。 - Lion789

5
你可以为你的警示对话框创建一个监听器,它使用接口来监听AlertDialogs的操作。
创建一个接口。
public class MyInterface {

    DialogReturn dialogReturn;

    public interface DialogReturn {

        void onDialogCompleted(boolean answer);
    }

    public void setListener(DialogReturn dialogReturn) {
        this.dialogReturn = dialogReturn;
    }

    public DialogReturn getListener() {
        return dialogReturn;

    }
}

现在,在你的类中实现你创建的接口,使用implements MyInterface.DialogReturn

然后你就可以设置监听器并让它像下面展示的那样工作了:

public class Main extends Activity implements MyInterface.DialogReturn{

    MyInterface myInterface;
    MyInterface.DialogReturn dialogReturn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                ....
        myInterface = new MyInterface();
        myInterface.setListener(this);
    }


   public void Confirm(Context context) {
        AlertDialog dialog = new AlertDialog.Builder(context).create();
        dialog.setTitle("Confirmation");
        dialog.setMessage("Choose Yes or No");
        dialog.setCancelable(false);
        dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                myInterface.getListener().onDialogCompleted(true);
            }
        });
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "No", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                myInterface.getListener().onDialogCompleted(false);
            }
        });
        dialog.setIcon(android.R.drawable.ic_dialog_alert);
        dialog.show();
         }


@Override
    public void onDialogCompleted(boolean answer) {
        Toast.makeText(Main.this, answer+"", Toast.LENGTH_LONG).show();
            if(answer)
            // do something
            else
            // do something
    }
}

我假设你的建议是有效的。但是,这是实现简单事情的一种复杂方式!你觉得呢? - ilomambo
1
是的,但如果我们理解了它并使其正常工作,这并不那么复杂。 - Lalit Poptani
2
@ilomambo <unsolicitedEditorial>欢迎来到Android!同样欢迎来到Java。</unsolicitedEditorial> - Peter Ajtai

1

在安卓系统中,阻塞运行线程等待用户回答“是”或“否”并不是一个好主意。

为了请求确认,您可以定义一个接收AsynTask的方法。如果用户按下确认按钮,则该方法执行该任务。

例如:

    //this method displays a confirm dialog. If 'yes' answer, runs 'yesTask', 
    //if 'no' answer, runs 'noTask'
    //notice than 'yesTask' and 'noTask' are AysncTask
    //'noTask' can be null, example: if you want to cancel when 'no answer'

    public static void confirm(Activity act, String title, String confirmText,
                       String noButtonText, String yesButtonText,
                       final AsyncTask<String, Void, Boolean> yesTask,
                       final AsyncTask<String, Void, Boolean> noTask) {

    AlertDialog dialog = new AlertDialog.Builder(act).create();
    dialog.setTitle(title);
    dialog.setMessage(confirmText);
    dialog.setCancelable(false);
    dialog.setButton(DialogInterface.BUTTON_POSITIVE, yesButtonText,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                yesTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            }
        });
    dialog.setButton(DialogInterface.BUTTON_NEGATIVE, noButtonText,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                if(noTask!=null) {
                    noTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                }

            }
        });
    dialog.setIcon(android.R.drawable.ic_dialog_alert);
    dialog.show();
}

您可以在您的活动中使用以下代码进行调用:

 YourTask yourTask =  new YourTask( ... );
 confirm( YourActivity.this, 
         "Confirm", 
         "Are you sure?", 
         "Cancel", 
         "Continue", 
         yourTask,
         null);

YourTask类必须继承AsyncTask


1
我发现在需要等待输入时使用 jDeferred 很有帮助。
它本质上相当于使用接口,但你可以创建完成和失败处理程序。这只是一个值得考虑的替代方案:
new ConfirmationDialog(mContext)
        .showConfirmation("Are you sure?", "Yes", "No")
        .done(new DoneCallback<Void>() {
            @Override
            public void onDone(Void aVoid) {
                ....
            }
        })
        .fail(new FailCallback<Void>() {

            @Override
            public void onFail(Void aVoid) {
                ...
            }
        });

实现:

public class ConfirmationDialog {


    private final Context mContext;
    private final DeferredObject<Void, Void, Void> mDeferred = new DeferredObject<Void, Void, Void>();

    public ConfirmationDialog(Context context) {
        mContext = context;
    }

    public Promise<Void, Void, Void> showConfirmation(String message, String positiveButton, String negativeButton) {
        AlertDialog dialog = new AlertDialog.Builder(mContext).create();
        dialog.setTitle("Alert");
        dialog.setMessage(message);
        dialog.setCancelable(false);
        dialog.setButton(DialogInterface.BUTTON_POSITIVE, positiveButton, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                mDeferred.resolve(null);
            }
        });
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, negativeButton, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                mDeferred.reject(null);
            }
        });
        dialog.setIcon(android.R.drawable.ic_dialog_alert);
        dialog.show();
        return mDeferred.promise();
    }

}

0

我尝试了所有的解决方案,我认为最简单和最干净的是第一个使用Runnable的解决方案。它支持在Cancel按钮监听器、OnBAckPressed()和onOptionsItemSelected()上显示对话框。

但是,按照描述的代码在点击BUTTON_POSITIVE时调用ans_false.run();,在点击BUTTON_NEGATIVE时调用ans_true.run();

这里是我用来解决这个问题的代码:

public class MyDialogs {

// private constructor
public Runnable answerTrue = null;
public Runnable answerFalse = null;

// Dialog. --------------------------------------------------------------

public boolean confirm(Activity act, String Title, String ConfirmText,
                       String noBtn, String yesBtn, Runnable yesProc, Runnable noProc) {
    answerTrue = yesProc;
    answerFalse= noProc;
    AlertDialog.Builder alert = new AlertDialog.Builder(act);
    alert.setTitle(Title);
    alert.setMessage(ConfirmText);
    alert.setCancelable(false);
    alert.setPositiveButton(R.string.button_positive, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            answerTrue.run();
        }
    });
    alert.setNegativeButton(R.string.button_negative, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            answerFalse.run();
        }
    });
    alert.show().getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
    return true;
}

}


0
在您的活动中声明一个名为“answer”的字段并对其进行赋值。类的字段对内部类可见,因此您可以这样做。

是的,我没有提到,但我需要该方法独立于其定义的类。不能使用类变量。我会更新问题以使其更清晰。 - ilomambo

0

我之前也曾苦恼于如何使用阻塞的确认对话框,最后通过使用一个阻塞队列终于解决了:

public static class BlockingConfirmDialog{

    private Activity context;

    BlockingQueue<Boolean> blockingQueue;

    public BlockingConfirmDialog(Activity activity) {
        super();
        this.context = activity;
        blockingQueue = new ArrayBlockingQueue<Boolean>(1);
    }

    public boolean confirm(final String title, final String message){

        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                new AlertDialog.Builder(context)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) { 
                        blockingQueue.add(true);
                    }
                 })
                 .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        blockingQueue.add(false);
                    }
                })
                 .show();
            }
        });

        try {
            return blockingQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }

    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接