可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
It seems to be there is no easy way to get an Alert dialog to return a simple value.
This code does not work (the answer variable cannot be set from within the listener, in fact it does not even compile)
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;
}
NOTE: It is important that the method is self contained, i.e., it does not depend on variables or constructs external to it. Just call it and get your answer, true or false.
So, what to do? This simple wish of returning true or false seems to be much more complicated than it deserves.
Also, the setButton method has the form:
dialog.setButton(int buttonId, String buttonText, Message msg)
But it is not clear how to use it, where is the meesage sent to, to whom, which handler is used?
回答1:
i have post similiar problem in this forum, but finally i get my answer.
my problem in that post is how to create separate confirm dialog class who can acces by other class or activity, so with that confirm dialog class we don't need to write long coding.
here's my answer.
First you must create 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;
}
}
And this is example to call it in another class
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");
}
};
}
}
回答2:
Well, I was going to say that I am very pleased with myself because I found a simple answer, all by myself!
But the truth is that although I find a way to return a value (which I show below). It is of no use.
The real problem is I wanted a synchronous Dialog, a dialog that waits for the user to answer before resuming your code after dialog.show()
.
There is no such beast in Android. All dialogs are asynchronous, so dialog.show()
only posts the dialog in some queue (I think) and continues. Thus you don't get your answer in time.
For all its worth (nothing) below you'll find how to set a value inside the method that builds the dialog. Maybe there are other uses for this technique, not related to the dialog lifecycle.
To give some related info, I'll say that if you replace
boolean answer;
with
final boolean answer;
it is possible to access the variable from within the listener, but it is not possible to assign it a new value, since it was declared as final.
Here comes the trick.
Define the variable as:
final boolean[] answer = new boolean[1];
Some of you already see why this will work. The final variable here is not the single element of the boolean array, is the array itself.
So now you can assign the array element [0] as you wish.
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int buttonId) {
answer[0] = true;
}
});
. . .
return answer[0];
And finally you can return it from your method.
回答3:
What you can do is create a Listener for your Alert Dialog that listens to AlertDialogs action using an Interface.
Create an Interface.
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;
}
}
Now, in your class just implement the Interface that you created using implements MyInterface.DialogReturn
then you can set the Listener and get it working as show below,
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
}
}
回答4:
I find that using jDeferred helps in cases where you want to wait for input.
It is essentially equivalent to using an interface, but instead you create done and fail handlers. Just an alternative to consider:
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) {
...
}
});
Implementation:
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();
}
}
回答5:
With Andriod, it is not a good idea to block the running thread by waiting for the user to say 'yes' or 'no'.
In order to ask for a confirmation, you can define a method that receives an AsynTask. The method executes that task if the user press the confirm button.
For example:
//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();
}
You can call it from your activity with:
YourTask yourTask = new YourTask( ... );
confirm( YourActivity.this,
"Confirm",
"Are you sure?",
"Cancel",
"Continue",
yourTask,
null);
YourTask
class must extend AsyncTask
回答6:
Declare a field 'answer' in your activity and set a value to it. Fields of a class are visible to inner classes, so you can do that.
回答7:
I was also struggling to use a blocking confirm dialog and I finally did it using a BlockingQueue :
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;
}
}
}
回答8:
I've tried all of the solutions and the easier and cleanest is by far the first solution with the Runnable, in my opinion. It supports the dialog on the Cancel button listener, the OnBAckPressed() and the onOptionsItemSelected().
The code as described though calls the ans_false.run(); when clicking the BUTTON_POSITIVE and the ans_true.run(); when clicking the BUTTON_NEGATIVE.
Here is the code I used to fix that problem:
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;
}
}