最近在做项目上做一些需求,途中遇到一个AlertDialog点击按钮问题,默认点击OK/cancel都会关闭对话框。但需求上要求在点击OK的时候做一些处理,根据处理结果来结束对话框。但是只要设置setPositiveButton("ok",this)了回调,点击ok就会关闭对话框。于是抱着好奇心去跟踪下源码:
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this;
}
把监听器保存到Builder类中的AlertController.AlertParams参数里面:
public static class Builder {
private final AlertController.AlertParams P;
接着调用create创建AlertDialog:
public AlertDialog create() {
// Context has already been wrapped with the appropriate theme.
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
创建AlertDialog的时候创建了AlertController类型的mAlert,调用P.apply(dialog.mAlert):
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null);
}
mPositiveButtonListener就是前面setPositiveButton设置的。调用AlertController中的setButton:
public void setButton(int whichButton, CharSequence text,
DialogInterface.OnClickListener listener, Message msg) {
if (msg == null && listener != null) {
msg = mHandler.obtainMessage(whichButton, listener);
}
switch (whichButton) {
case DialogInterface.BUTTON_POSITIVE:
mButtonPositiveText = text;
mButtonPositiveMessage = msg;
看到监听器保存到了消息mButtonPositiveMessage里面。
接着调用alertDialog.show(),show函数中会调用onCreate方法:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
进入AlertController中的installContent函数:
public void installContent() {
int contentView = selectContentView();
mWindow.setContentView(contentView);
setupView();
}
在setupView中调用setupButtons方法:
private void setupButtons(ViewGroup buttonPanel) {
int BIT_BUTTON_POSITIVE = 1;
int BIT_BUTTON_NEGATIVE = 2;
int BIT_BUTTON_NEUTRAL = 4;
int whichButtons = 0;
mButtonPositive = (Button) buttonPanel.findViewById(android.R.id.button1);
mButtonPositive.setOnClickListener(mButtonHandler);
主要还是给按钮设置监听器:
private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
@Override
public void onClick(View v) {
final Message m;
if (v == mButtonPositive && mButtonPositiveMessage != null) {
m = Message.obtain(mButtonPositiveMessage);
} else if (v == mButtonNegative && mButtonNegativeMessage != null) {
m = Message.obtain(mButtonNegativeMessage);
} else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
m = Message.obtain(mButtonNeutralMessage);
} else {
m = null;
}
if (m != null) {
m.sendToTarget();
}
// Post a message so we dismiss after the above handlers are executed
mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
.sendToTarget();
}
};
当我们点击OK按钮会发送消息到handler:
private static final class ButtonHandler extends Handler {
// Button clicks have Message.what as the BUTTON{1,2,3} constant
private static final int MSG_DISMISS_DIALOG = 1;
private WeakReference<DialogInterface> mDialog;
public ButtonHandler(DialogInterface dialog) {
mDialog = new WeakReference<>(dialog);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE:
case DialogInterface.BUTTON_NEUTRAL:
((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
break;
case MSG_DISMISS_DIALOG:
((DialogInterface) msg.obj).dismiss();
}
}
首先m.sendToTarget();会调用((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);在我们设置的监听器的地方处理。然后调用 mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
.sendToTarget();
将对话框销毁了。看来是内部帮我们把对话框给关闭了。消息处理我们也无法修改。只能重新给button设置监听器了。下面的方案可以解决:
AlertDialog.Builder builder = new AlertDialog.Builder(this).setPositiveButton("ok",null)
.setNegativeButton("cancel", null).setMessage("telkajslkdjslkaj");
final AlertDialog alertDialog = builder.create();
alertDialog.show();
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// alertDialog.dismiss();
}
});
这里必须先调用show函数,不然获取的button会为null。重新设置监听器,等于是覆盖了setupButtons中的设置。