Carson帶你學Android:手把手帶你深入源碼了解Dialog窗口機制

概述

本文將通過 Dialog 的創建、展示 & 銷毀過程 詳細說明 Dialog 的窗口機制


分析內容

// 1. 創建
Dialog dialog = new ProgressDialog(context);

// 2. 展示
dialog.show();

// 3. 銷毀
dialog.cancel();
dialog.dmiss();

Dialog創建

  1. Dialog一般在Acitivty啟動,所以傳入的是Activity的Context
  2. 任何創建方法都是基于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博客

相關系列文章閱讀
Carson帶你學Android:學習方法
Carson帶你學Android:四大組件
Carson帶你學Android:自定義View
Carson帶你學Android:異步-多線程
Carson帶你學Android:性能優化
Carson帶你學Android:動畫


歡迎關注Carson_Ho的簡書

不定期分享關于安卓開發的干貨,追求短、平、快,但卻不缺深度


請點贊!因為你的鼓勵是我寫作的最大動力!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。