概述
本文將通過 Dialog 的創建、展示 & 銷燬過程 詳細說明 Dialog 的窗口機制
分析內容
// 1. 創建
Dialog dialog = new ProgressDialog(context);
// 2. 展示
dialog.show();
// 3. 銷燬
dialog.cancel();
dialog.dmiss();
Dialog創建
- Dialog一般在Acitivty啓動,所以傳入的是Activity的Context
- 任何創建方法都是基於Dialog基類,所以下面分析的源碼是Dialog基類
// 具體使用
Dialog dialog = new ProgressDialog(context);
// 源碼分析
public class Dialog implements DialogInterface, Window.Callback,KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
// ...
// 構造函數最終都調運了該默認的構造函數
Dialog(Context context, int theme, boolean createContextThemeWrapper) {
// mContext參數是創建時從外部傳入的Activity context對象值
// 步驟1. 獲取WindowManager對象
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// 步驟2. 爲Dialog創建新的Window
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
// 步驟3. 關聯WindowManager與新Window
// 注:第二個參數token爲null,即一個Window屬於Dialog的話,那麼該Window的傳入的mAppToken對象是null,Dialog沒有自己的token
w.setWindowManager(mWindowManager, null, null);
}
......
}
源碼說明
- 步驟1:因爲 context 是Activity,所以獲取到的 WindowManager 屬於 Activity,所以** Dialog 與 Activity 共用一個 WindowManager 對象**
- 步驟2:獲得 Activity 的WindowManager對象後,Dialog 又新建了一個 Window對象(PhoneWindow 類型,創建過程類似於 Activity 的 Window 創建過程)
- 步驟3:將新創建 Dialog 的 window 關聯到 Activity 的 WindowManager。特別注意的是:關於AppToken,只是Window的傳入的mAppToken對象是null,但不代表Dialog的window無token,下面會詳細說明
重要結論
- 結論1:Dialog 與 Activity 共用一個 WindowManager 對象
- 結論2:Dialog 擁有自己的窗口 Window(PhoneWindow 類型)
- 結論3:Dialog 的 Window 由附屬的 Acitivty WindowManager 對象統一管理
Dialog展示
// 具體使用
dialog.show();
// 源碼分析
public void show() {
// ....
// 1. 調用 Dialog的onCreate()
dispatchOnCreate(null);
// 2. 調用Dialog的onStart()
onStart();
// 3. 獲取當前新Window的DecorView對象(類似於Activity)
mDecor = mWindow.getDecorView();
// 4. 獲取新Window的WindowManager.LayoutParams參數
WindowManager.LayoutParams l = mWindow.getAttributes();
// 5. 把一個View添加到與Activity共用的windowManager裏
mWindowManager.addView(mDecor, l);
}
源碼分析
- 步驟3:Dialog獲取當前新Window的DecorView對象時過程類似於Activity,所以有一種自定義Dialog佈局的方式就是重寫Dialog的onCreate方法,使用setContentView傳入佈局,類似於 Activity。
- 步驟4:由於Dialog 與 Activity 共用一個 WindowManager 對象,所以Activity與Dialog共用同一個mAppToken值(只是Dialog和Activity的Window對象不同)。
- 步驟5:添加過程與Activity 窗口添加過程 保持一致。
Dialog 銷燬
既然添加過程與Activity 窗口添加過程 保持一致,那麼不展示 / 銷燬過程也是跟Activity 窗口銷燬過程 十分類似
// 具體使用
dialog.cancel();
dialog.dmiss();
// 源碼分析
// 上述兩個方法最終都會回調:dismissDialog()
void dismissDialog() {
//...
mWindowManager.removeViewImmediate(mDecor);
}
mWindowManager 實際上是 WindowManagerImpl 的實例,所以這裏的 removeViewImmediate()就是 WindowManagerImpl 中移除 View 的方法,跟Activity 窗口銷燬過程 十分類似,這裏就不繼續展開說明了。
關於Dialog的窗口機制講解到這裏。
總結
- 本文通過源碼詳細解析了 Dialog的窗口機制
- 接下來推出的文章,我將繼續講解
Android
的相關知識,感興趣的讀者可以繼續關注我的博客哦:Carson_Ho的Android博客
請點贊!因爲你們的贊同/鼓勵是我寫作的最大動力!
相關文章閱讀
Android開發:最全面、最易懂的Android屏幕適配解決方案
Android開發:史上最全的Android消息推送解決方案
Android開發:最全面、最易懂的Webview詳解
Android開發:JSON簡介及最全面解析方法!
Android四大組件:Service服務史上最全面解析
Android四大組件:BroadcastReceiver史上最全面解析
歡迎關注Carson_Ho的簡書!
不定期分享關於安卓開發的乾貨,追求短、平、快,但卻不缺深度。