Android系統(tǒng)原理與源碼分析方案
出處:awey 發(fā)布于:2011-09-03 20:44:44
本文以下就是如何隨心所欲地控制AlertDialog的介紹。
現(xiàn)在我們來看看個(gè)需求:如果某個(gè)應(yīng)用需要彈出一個(gè)對(duì)話框。當(dāng)單擊“確定“按鈕時(shí)完成某些工作,如果這些工作失敗,對(duì)話框不能關(guān)閉。而當(dāng)成功完成工作后,則關(guān)閉對(duì)話框。當(dāng)然,無論何程度情況,單擊“取消”按鈕都會(huì)關(guān)閉對(duì)話框。
這個(gè)需求并不復(fù)雜,也并不過分。但使用過AlertDialog的讀者都知道,無論單擊的哪個(gè)按鈕,無論按鈕單擊事件的執(zhí)行情況如何,對(duì)話框是肯定要關(guān)閉的。也就是說,用戶無法控制對(duì)話框的關(guān)閉動(dòng)作。實(shí)際上,關(guān)閉對(duì)話框的動(dòng)作已經(jīng)在Android SDK寫死了,并且未給使用者留有任何接口。但我的座右銘是“宇宙中沒有什么是不能控制的”。
既然要控制對(duì)放框的關(guān)閉行為,首先就得分析是哪些類、哪些代碼使這個(gè)對(duì)話框關(guān)閉的。進(jìn)入AlertDialog類的源代碼。在AlertDialog中只定義了一個(gè)變量:mAlert。這個(gè)變量是AlertCONtroller類型。AlertController類是Android的內(nèi)部類,在com.android.internal.app包中,無法通過普通的方式訪問。也無法在Eclipse中通過按Ctrl鍵跟蹤進(jìn)源代碼。但可以直接在Android源代碼中找到AlertController.java。我們?cè)倩氐紸lertDialog類中。AlertDialog類實(shí)際上只是一個(gè)架子。象設(shè)置按鈕、設(shè)置標(biāo)題等工作都是由AlertController類完成的。因此,AlertController類才是關(guān)鍵。
找到AlertController.java文件。打開后不要感到頭暈哦,這個(gè)文件中的代碼是很多地。不過這么多代碼對(duì)本文的主題也沒什么用處。下面就找一下控制按鈕的代碼。
在AlertController類的開頭就會(huì)看到如下的代碼:
View.OnClickListener mButtonHandler = new View.OnClickListener() {
public void onClick{
Message m = null;
if {
m = Message.obtain;
} else if {
m = Message.obtain;
} else if {
m = Message.obtain;
}
if {
m.sendToTarget();
}
// Post a message so we dismiss after the above handlers are executed
mHandler.obtainMessage
.sendToTarget();
}
};
從這段代碼中可以猜出來,前幾行代碼用來觸發(fā)對(duì)話框中的三個(gè)按鈕的單擊事件,而的代碼則用來關(guān)閉對(duì)話框。
mHandler.obtainMessage
.sendToTarget();
上面的代碼并不是直接來關(guān)閉對(duì)話框的,而是通過一個(gè)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 {
mDialog = new WeakReference《DialogInterface》;
}
@Override
public void handleMessage {
switch {
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處理對(duì)話框按鈕時(shí)會(huì)為每一個(gè)按鈕添加一個(gè)onclick事件。而這個(gè)事件類的對(duì)象實(shí)例就是上面的mButtonHandler。在這個(gè)單擊事件中首先會(huì)通過發(fā)送消息的方式調(diào)用為按鈕設(shè)置的單擊事件(也就是通過setPositiveButton等方法的第二個(gè)參數(shù)設(shè)置的單擊事件),在觸發(fā)完按鈕的單擊事件后,會(huì)通過發(fā)送消息的方式調(diào)用dismiss方法來關(guān)閉對(duì)話框。而在AlertController類中定義了一個(gè)全局的mHandler變量。在AlertController類中通過ButtonHandler類來對(duì)象來為mHandler賦值。因此,我們只要使用我們自己Handler對(duì)象替換ButtonHandler就可以阻止調(diào)用dismiss方法來關(guān)閉對(duì)話框。下面先在自己的程序中建立一個(gè)新的ButtonHandler類。
class ButtonHandler extends Handler
{
private WeakReference《DialogInterface》 mDialog;
public ButtonHandler
{
mDialog = new WeakReference《DialogInterface》;
}
@Override
public
void handleMessage
{
switch
{
case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE:
case DialogInterface.BUTTON_NEUTRAL:
((DialogInterface.OnClickListener) msg.obj)。onClick(mDialog
.get(), msg.what);
break;
}
}
}
我們可以看到,上面的類和AlertController中的ButtonHandler類很像,只是支掉了switch語(yǔ)句的一個(gè)case子句和相關(guān)的代碼。
由于mHandler是private變量,因此,在這里需要使用Java的反射技術(shù)來為mHandler賦值。由于在AlertDialog類中的mAlert變量同樣也是private,因此,也需要使用同樣的反射技術(shù)來獲得mAlert變量。代碼如下:
先建立一個(gè)AlertDialog對(duì)象
AlertDialog alertDialog = new AlertDialog.Builder
.setTitle
.setMessage
.setIcon
.setPositiveButton
new OnClickListener()
{
@Override
public void onClick
{
}
})。setNegativeButton()
{
@Override
public void onClick
{
dialog.dismiss();
}
})。create();
上面的對(duì)話框很普通,單擊哪個(gè)按鈕都會(huì)關(guān)閉對(duì)話框。下面在調(diào)用show方法之前來修改一個(gè)mHandler變量的值,OK,下面我們就來見證奇跡的時(shí)刻。
try
{
Field field = alertDialog1.getClass()。getDeclaredField;
field.setAccessible;
//
獲得mAlert變量的值
Object obj = field.get;
field = obj.getClass()。getDeclaredField;
field.setAccessible;
//
修改mHandler變量的值,使用新的ButtonHandler類
field.set; }
catch {
}
//
顯示對(duì)話框
alertDialog.show();
我們發(fā)現(xiàn),如果加上try
catch語(yǔ)句,單擊對(duì)話框中的確定按鈕不會(huì)關(guān)閉對(duì)話框,單擊取消按鈕則會(huì)關(guān)閉對(duì)話框。如果去了try…catch代碼段,對(duì)話框又會(huì)恢復(fù)正常了。
以上代碼解決了問題,但需要的代碼還比較多,所以我們采用了另一種方法來阻止關(guān)閉對(duì)話框。
這種方法需要用點(diǎn)技巧。由于系統(tǒng)通過調(diào)用dismiss來關(guān)閉對(duì)話框,那么我們可以在dismiss方法上做點(diǎn)文章。在系統(tǒng)調(diào)用dismiss方法時(shí)會(huì)首先判斷對(duì)話框是否已經(jīng)關(guān)閉,如果對(duì)話框已經(jīng)關(guān)閉了,就會(huì)退出dismiss方法而不再繼續(xù)關(guān)閉對(duì)話框了。因此,我們可以欺騙一下系統(tǒng),當(dāng)調(diào)用dismiss方法時(shí)我們可以讓系統(tǒng)以為對(duì)話框已經(jīng)關(guān)閉(雖然對(duì)話框還沒有關(guān)閉),這樣dismiss方法就失效了,這樣即使系統(tǒng)調(diào)用了dismiss方法也無法關(guān)閉對(duì)話框了。
下面讓我們回到AlertDialog的源代碼中,再繼續(xù)跟蹤到AlertDialog的父類Dialog的源代碼中。找到dismissDialog方法。實(shí)際上,dismiss方法是通過dismissDialog方法來關(guān)閉對(duì)話框的,dismissDialog方法的代碼如下:
private
void dismissDialog() {
if {
if Log.v;
return;
}
if {
if Log.v;
return;
}
mWindowManager.removeView;
mDecor = null;
mWindow.closeAllPanels();
onStop();
mShowing = false;
sendDismissMessage();
}
該方法后面的代碼不用管它,先看if{…}這段代碼。這個(gè)mShowing變量就是判斷對(duì)話框是否已關(guān)閉的。因此,我們?cè)诖a中通過設(shè)置這個(gè)變量就可以使系統(tǒng)認(rèn)為對(duì)話框已經(jīng)關(guān)閉,就不再繼續(xù)關(guān)閉對(duì)話框了。由于mShowing也是private變量,因此,也需要反射技術(shù)來設(shè)置這個(gè)變量。我們可以在對(duì)話框按鈕的單擊事件中設(shè)置mShowing,代碼如下:
try
{
Field field = dialog.getClass()
.getSuperclass()。getDeclaredField;
field.setAccessible(true);
//
將mShowing變量設(shè)為false,表示對(duì)話框已關(guān)閉
field.set;
dialog.dismiss();
}
catch
{
}
將上面的代碼加到哪個(gè)按鈕的單擊事件代碼中,哪個(gè)按鈕就再也無法關(guān)閉對(duì)話框了。如果要關(guān)閉對(duì)話框,只需再將mShowing設(shè)為true即可。要注意的是,在一個(gè)按鈕里設(shè)置了mShowing變量,也會(huì)影響另一個(gè)按鈕的關(guān)閉對(duì)話框功能,因此,需要在每一個(gè)按鈕的單擊事件里都設(shè)置mShowing變量的值。
版權(quán)與免責(zé)聲明
凡本網(wǎng)注明“出處:維庫(kù)電子市場(chǎng)網(wǎng)”的所有作品,版權(quán)均屬于維庫(kù)電子市場(chǎng)網(wǎng),轉(zhuǎn)載請(qǐng)必須注明維庫(kù)電子市場(chǎng)網(wǎng),http://hbjingang.com,違反者本網(wǎng)將追究相關(guān)法律責(zé)任。
本網(wǎng)轉(zhuǎn)載并注明自其它出處的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點(diǎn)或證實(shí)其內(nèi)容的真實(shí)性,不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個(gè)人從本網(wǎng)轉(zhuǎn)載時(shí),必須保留本網(wǎng)注明的作品出處,并自負(fù)版權(quán)等法律責(zé)任。
如涉及作品內(nèi)容、版權(quán)等問題,請(qǐng)?jiān)谧髌钒l(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。
- ARM技術(shù)架構(gòu)與應(yīng)用開發(fā)實(shí)踐指南2026/1/6 10:40:19
- 嵌入式實(shí)時(shí)操作系統(tǒng)(RTOS)選型與移植技術(shù)指南2025/12/31 10:42:31
- 工業(yè)嵌入式系統(tǒng):通信接口技術(shù)選型與抗干擾設(shè)計(jì)實(shí)踐2025/12/15 14:36:53
- 深入解析嵌入式 OPENAMP 框架:開啟異核通信新時(shí)代2025/7/22 16:27:29
- 一文快速了解OPENWRT基礎(chǔ)知識(shí)2025/7/14 16:59:04
- 高速PCB阻抗控制核心實(shí)操規(guī)范
- 高速數(shù)字系統(tǒng)(如DDR、SerDes)中的信號(hào)完整性濾波
- MOSFET在UPS電源中的應(yīng)用解析
- 電源管理IC在物聯(lián)網(wǎng)設(shè)備中的應(yīng)用
- SMT連接器焊接缺陷分析
- MOSFET在汽車電子中的應(yīng)用要求
- 通信設(shè)備電源管理IC應(yīng)用解析
- 通信設(shè)備連接器選型與設(shè)計(jì)
- PCB電磁兼容性(EMC)設(shè)計(jì)核心實(shí)操規(guī)范
- 物聯(lián)網(wǎng)節(jié)點(diǎn)低功耗設(shè)計(jì):信號(hào)鏈中的濾波與功耗管理









