真的有外星人嗎
眾所周知,AlertDialog類用於顯示對話框。關於AlertDialog的基本用法在這裡就不詳細介紹瞭,網上有很多,讀者可以自己搜索。那麼本文要介紹的是如何隨心所欲地控制AlertDialog。
現在我們來看看第一個需求:如果某個應用需要彈出一個對話框。當單擊“確定“按鈕時完成某些工作,如果這些工作失敗,對話框不能關閉。而當成功完成工作後,則關閉對話框。當然,無論何程度情況,單擊“取消”按鈕都會關閉對話框。
這個需求並不復雜,也並不過分(雖然我們可以自己弄個Activity來完成這個工作,也可在View上自己放按鈕,但這顯示有些大炮打蚊子瞭,如果對話框上隻有一行文本,費這麼多勁太不值瞭)。但使用過AlertDialog的讀者都知道,無論單擊的哪個按鈕,無論按鈕單擊事件的執行情況如何,對話框是肯定要關閉的。也就是說,用戶無法控制對話框的關閉動作。實際上,關閉對話框的動作已經在Android SDK寫死瞭,並且未給使用者留有任何接口。但我的座右銘是“宇宙中沒有什麼是不能控制的”。
既然要控制對放框的關閉行為,首先就得分析是哪些類、哪些代碼使這個對話框關閉的。進入AlertDialog類的源代碼。在AlertDialog中隻定義瞭一個變量:mAlert。這個變量是AlertController類型。AlertController類是Android的內部類,在com.android.internal.app包中,無法通過普通的方式訪問。也無法在Eclipse中通過按Ctrl鍵跟蹤進源代碼。但可以直接在Android源代碼中找到AlertController.java。我們再回到AlertDialog類中。AlertDialog類實際上隻是一個架子。象設置按鈕、設置標題等工作都是由AlertController類完成的。因此,AlertController類才是關鍵。
找到AlertController.java文件。打開後不要感到頭暈哦,這個文件中的代碼是很多地。不過這麼多代碼對本文的主題也沒什麼用處。下面就找一下控制按鈕的代碼。
在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();
}
};
從這段代碼中可以猜出來,前幾行代碼用來觸發對話框中的三個按鈕( Positive 、 Negative 和 Neutral )的單擊事件,而最後的代碼則用來關閉對話框(因為我們發現瞭 MSG_DISMISS_DIALOG 、猜出來的)。
mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
.sendToTarget();
上面的代碼並不是直接來關閉對話框的,而是通過一個 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 < 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();
}
}
}
從上面代碼的最後可以找到 ((DialogInterface) msg.obj).dismiss();。現在看瞭這麼多源代碼,我們來總結一下對話框按鈕單擊事件的處理過程。在AlertController處理對話框按鈕時會為每一個按鈕添加一個onclick事件。而這個事件類的對象實例就是上面的mButtonHandler。在這個單擊事件中首先會通過發送消息的方式調用為按鈕設置的單擊事件(也就是通過setPositiveButton等方法的第二個參數設置的單擊事件),在觸發完按鈕的單擊事件後,會通過發送消息的方式調用dismiss方法來關閉對話框。而在AlertController類中定義瞭一個全局的mHandler變量。在AlertController類中通過ButtonHandler類來對象來為mHandler賦值。因此,我們隻要使用我們自己Handler對象替換ButtonHandler就可以阻止調用dismiss方法來關閉對話框。下面先在自己的程序中建立一個新的ButtonHandler類(也可叫其他的名)。
class ButtonHandler extends Handler
{
private WeakReference < DialogInterface > mDialog;
&n