AlertDialog
下面是自我提问。。。
2.如何处理OnDismissListener, OnCancelListener, OnShowListener和OnKeyListener这些消息的?
自我总结:
窗口创建过程
一般当你调用AlertDialog dlg = new AlertDialog(context);
的时候最终在Dialog类的构造函数里面创建窗口,代码如下:
Dialog(Context context, int theme, boolean createContextThemeWrapper) {
if (createContextThemeWrapper) {
if (theme == 0) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
outValue, true);
theme = outValue.resourceId;
}
mContext = new ContextThemeWrapper(context, theme);
} else {
mContext = context;
}
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
}
当我们调用
setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
// TODO Auto-generated method stub
}
});时,其内部实现为:
public void setOnShowListener(OnShowListener listener) {
if (listener != null) {
mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
} else {
mShowMessage = null;
}
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
public static Message obtain(Handler h, int what, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.obj = obj;
return m;
}
这时mListenerHandler获取一个为SHOW的消息,并赋给mShowMessage。其中mShowMessage的Target就是mListenerHandler。
然后继续调用
dlg.show();
下面有:
public void show() {
// ...
try {
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
} finally {
}
}
private void sendShowMessage() {
if (mShowMessage != null) {
// Obtain a new message so this dialog can be re-used
Message.obtain(mShowMessage).sendToTarget();
}
}看到没,刚才我们调用setOnShowListener的时候,已经给mShowMessage赋过值了。
这时,mListenerHandler的handleMessage会收到消息SHOW。
我们来看下ListenerHandler的handleMessage的处理函数:
private static final class ListenersHandler extends Handler {
private WeakReference<DialogInterface> mDialog;
public ListenersHandler(Dialog dialog) {
mDialog = new WeakReference<DialogInterface>(dialog);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DISMISS:
((OnDismissListener) msg.obj).onDismiss(mDialog.get());
break;
case CANCEL:
((OnCancelListener) msg.obj).onCancel(mDialog.get());
break;
case SHOW:
((OnShowListener) msg.obj).onShow(mDialog.get());
break;
}
}
}这里通过Callback触发用户定义的Listener。。。
其他的诸如Dismiss, Cancel是一样的道理。
OK,这里完成了Dialog的Dismiss, Cancel, 以及Show的事件监听的调用过程。。。
下面打算分析一下AlertDialog特有的3个按钮(BUTTON_POSITIVE,BUTTON_NEGATIVE,BUTTON_NEUTRAL)的调用过程。
一般我们通过如下代码设定来给一个AlertDialog设定按钮以及事件监听接口。
setButton(DialogInterface.BUTTON_NEUTRAL,
"Neutral",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Log.d("java-hh", "AlertDialog -- BUTTON_NEUTRAL click");
}
});
内部跟踪代码得到:
public void setButton(int whichButton, CharSequence text, OnClickListener listener) {
mAlert.setButton(whichButton, text, listener, null);
}
继续跟踪:
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;
break;
case DialogInterface.BUTTON_NEGATIVE:
mButtonNegativeText = text;
mButtonNegativeMessage = msg;
break;
case DialogInterface.BUTTON_NEUTRAL:
mButtonNeutralText = text;
mButtonNeutralMessage = msg;
break;
default:
throw new IllegalArgumentException("Button does not exist");
}
}
这里同样有一个Handler,我们获取一个Target为Handler的消息(该消息ID为whichButton,即按钮的ID),
然后使用成员变量mButtonNeutralMessage保存该消息。但是何时该消息才会被调用呢?看代码:
package com.android.internal.app;
public class AlertController ... {
// ...
View.OnClickListener mButtonHandler = new View.OnClickListener() {
public void onClick(View v) {
Message m = null;
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);
}
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();
}
};
// ...
}
原来有个mButtonHandler一开始就将3个按钮的消息处理函数设置好了,然后会检查用于是否设置了相关的消息监听接口。
如果用户设置了,直接触发该消息(
m.sendToTarget();)。最后发送一个MSG_DISMISS_DIALOG来关闭AlertDialog,这就是为什么单击Cancel, OK, Neutral都能关闭AlertDialog的原因。
下面再看下mHandler消息处理函数的实现:
mHandler = new ButtonHandler(di);
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<DialogInterface>(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();
}
}
}
怎么样?很清楚了吧,3个按钮消息,外加一个关闭AlertDialog的dismiss消息处理函数。
需要考虑的是ButtonHandler里面使用WeakReference。我估计是因为考虑到如下的情况:
用户单击了OK按钮,Handler还未处理到
case DialogInterface.BUTTON_POSITIVE:而此时Dialog已经因为某中特殊情况被关闭了,此时mDialog会为NULL的。。

本文详细解析了AlertDialog的窗口创建过程,包括如何处理各种消息监听,如显示、取消、关闭等事件,以及如何自定义按钮的设置与响应。通过分析核心代码流程,揭示了AlertDialog背后的工作原理。
4437

被折叠的 条评论
为什么被折叠?



