在Android中,Dialog是一個非常重要的UI, 它可以方便的給使用者提示,用最簡潔的方式向使用者展示資訊, 以下的圖片是Dialog的一個整體架構,通過它,可以總體對Dialog有一個很清晰的認識.
從這張圖中可以看到,Dialog為父類, 其下有最重要的, 我們最常用的AlertDilog, 而AlertDialog的子類,則是由DatPicker, ProgressDialog,TimePick來組成.
這幾個子類都是我們在程式開發中最常用的,因此要重點理解, 我們可以試著想像一下,如下幾個問題的答案
<1> 怎麼產生一個Dialog?
<2> Dialog與Activity是什麼關係? 為什麼顯示Dialog的時候,Activity就失去了焦點,不能被點擊,在系統內部到底是怎麼管理他們的關係的?
我們以ProgressDialog為例, 通過分析其源碼,讓我們徹底理解它的內部運行機制
<1> 怎麼產生一個ProgressDialog?
通過開啟ProgressDialog的源碼, 可以看到它有2個構造方法,
ProgressDialog(Context context)
ProgressDialog(Context context,int theme)
參數解釋: context:說明它是依靠Context,必須通過一個Context來建立它, 第二個參數theme: 此dialog的主題.
另外我們還可以發現 有四個靜態show方法,他們只是參數不同,
show(Context context,CharSequence title,CharSequence message);
show(Context context,CharSequence title,CharSequence message,boolean indeterminate);
其時,我們只看最後一個靜態方法就行了,因為三個靜態方法,最終會調用最後一個參數最多的show靜態方法來完成功能.
它所實現的功能是:
ProgressDialog dialog=new ProgressDiaog(context);
...
...
...
dialog.show();
這其實跟,我們調用構造方法是一樣的.
到這一步,僅僅是知道了,怎麼調用產生的ProgressDialog的,但具體內部的細節呢。還要看onCreate()方法, 此方法才是真正能產生progressDialogr 地方, 它跟Activity中的onCreate()方法是一樣的,就是初始化的時候調用, 我們看其源碼如下:
首先看到的是一個名叫 mViewUpdatehandler的 Handler, 這個Handler主要用來更新progress的值, (百分比),接著往下看...
有這麼一句: View view=inflater.inflate(R.layout.alert_dialog_press,null);
很明顯,這就是我們看到的,顯示在dialog中轉圈的那個東東. 然而,這個alert_dialog_pross檔案是在com.android.internal.R 包中,屬於系統定義的ui設定檔.
最後調用 setView(view)方法來, 來把view顯示在Dialog上。
因此,我們同樣也可以實現自訂一個dialog.xml檔案,來調用setView()方法顯示上來.
這個setView()方法是AlertDialog類中定義的,等會再解釋!
這就是我們平時所見到的 ProgressDialog。分析完畢。
AlertDialog
接下來,我們開始分析ProgressDialog的父類 AlertDialog.
開啟源碼,首先映入眼帘的是 三個構造方法,但這三個構造方法都是protected類型的,
可見,不允許我們直接執行個體化AlertDialog. 因此,我們再看別的有沒有方法.可以執行個體化
再仔細一看,發現一個變數 ,
AlertController mAlert; 這個才是我們今天的主角,重點研究它.
mAlert的定義是在 ,以上我們提到的AlertDialog的建構函式,
此外,我們還發現,AlertDialog中幾乎所有的方法都是通過這個mAlert變數來操作的,
也就是說,AlertDialog是一個空殼,並沒有實際的作用, 它的實質是AlertController類.
就是我剛才說的 "主角" 。 而Alertcontroller的源碼,是Android系統內建的,我們需要花費一番力氣去尋找.
在往下看,AlertDialog 類中,發現一個靜態類 Builder, 通過這個類,我們也可以直接建立一個Dialog,
Builder靜態類中也同樣有一個AlertController.Alertparams的類的對象 P,我們再看Builder的源碼,它裡面可以設定所有Dialog的的方法,包括
setTitle(CharSequence title)
setMessage(int messageId);
setIcon(int iconId);
setPositiveButton()
...
...
....
等,我們看這些方法的的內部實現,全部是針對它的內建對象P 來實現的, 也就是我們所調用的這些方法,最終結果實際上是用在了AlertController.AlertParams 類的對象P 身上,
,而別外還有一個有趣的現象,這些方法的傳回值都是Builder對象, 也就是說,我們可以連級調用此方法,
而顯示一個Dialog,僅僅調用這些set 方法,還不夠,最後還差一步, 就是調用create()方法,這個方法是最後調用的,也就是建立對話方塊, 我們看,create方法中都做了那些動作
public AlertDialog create() {
final AlertDialog dialog =new AlertDialog(p.mContext);
p.apply(dialog.mAlert)
dialog.setCancelable(P.mCancelable);
return dialog;
}
這個是create()的實現,我們可以很直觀地看出是它幫我們建立了一個AlertDialog對象,
這裡的p, 就是我們建立的AlertController.Alertparams的對象,
而在AlertDialog dialog=new AlertDialog(p.mContext); 這句代碼中,定義Dialog的同時也定義了 一個AlertController 的對象 mAlert;
在第二句代碼中,p.apply(dialog.mAlert) ,我們跟蹤過去,看下,哈哈,原來是,我們剛才調用的set方法的值,又還原給新定義的dialog中的 mAlert對象了, 這下明白了,原來 P只不過是一個 "屁" ,暫時的存放資料的對象,只要我們調用create方法,P就會乖乖的把資料交給dialog對象,
除了create方法以外, 還有一個show() 方法,實現如下
public AlertDialog show() {
AlertDialog dialog=create();
dialog.show();
return dialog;
}
我們可以看出,show() 也是調用的 create方法.
由以下的分析,我們就可能輕鬆理解,如下我們常用的語句了,
return new AlertDialog.Builder(context).
setIcon(R.drawable.alert_icon).
setTitle(R.string.alert_str)
.create() ;
這是我們平時用到的產生Dialog