理解Window和WindowManager


Window表示一個窗口的概念,Window是一個抽象類,它的具體實現是PhoneWindow。創建一個Window,需要通過WindowManager即可完成,WindowManager是外界訪問Window的入口,Window具體實現位於WindowManagerService中,WindowManager和WindowManagerService的交互是一個IPC的過程。Android中,所有的視圖都是通過Window來呈現,不管是Activity、Dialog、還是Toast,它們的視圖實際上都是附加在Window上,因此Window是實際View的直接管理者,單擊事件由Window傳遞給DecorView,然后再由DecorView傳遞給我們的View,就連Activity的設置視圖方法setContentView在底層也是通過Window來完成的。

Window和WindowManager

添加一個Window的過程,重點代碼是:

mWindowManager.addView(mFLoatingButton,mLayoutParams);

WindowManager.LayoutParams中有兩個flags和type參數。

Flags參數有三個Window屬性

  • FLAG_NOT_FOCUSABLE。表示Window不需要獲取焦點,也不需要接收各種輸入事件,最終事件會直接傳遞給下層的具有焦點的Window
  • FLAG_NOT_TOUCH_MODAL。在此模式下,系統會將當前Window區域以外的單擊事件傳遞給底層的Window,當前Window區域以內的單擊事件則自己處理,這個標記很重要,一般來說都需要開啟此標記,否則其他Window將無法收到單擊事件
  • FLAG_SHOW_WHEN_LOCKED。開啟此模式可以讓Window顯示在鎖屏的界面上。

Type參數表示Window的類型,有三種類型,分別是應用Window,子Window和系統Window,應用類Window對應一個Activity,子Window不能單獨存在,它需要附屬在特定的父Window之中,比如常見的Dialog就是一個子Window,系統Window是需要聲明權限在能創建的Window,比如Toast和系統狀態欄這些都是系統Window。

Window是分層的,每個Window都有對應的z-ordered,層級大的會覆蓋在層級小的Window的上面,在三類Window中,應用類的Window的層級范圍是1-99,子Window的層級范圍是1000-1999,系統Window的層級的范圍是2000-2999,這些層級范圍對應着WindowManager.LayoutParams的Type參數。如想要Window位於所有Window的最頂層,那么采用較大的層級即可。很顯然系統Window層級是最大的,而且系統層級有很多值。

WindowManager所提供的功能很簡單,常用有三個方法,即添加View,更新View和刪除View,這三個方法定義在ViewManager中,而WindowManager繼承了ViewManager。

Window的內部機制

Window是一個抽象的概念,每一個Window都對應着一個View和一個ViewRootImpl,Window和View通過ViewRootImpl來建立聯系,說明View才是Window存在的實體,在實際使用中無法直接訪問Window,對Window的訪問必須通過WindowManager。

Window的添加過程

Window的添加過程需要通過WindowManager的addView來實現,WindowManager是一個接口,它的真正實現是WindowManagerImpl類。

@Override
public void addView(View view,ViewGroup.LayoutParams params){
  mGlobal.addView(view,params,mDisplay,mParentWindow);
}

@Override
public void updateViewLayout(View view,ViewGroup.LayoutParams params){
  mGlobal.updateViewLayout(view,params);
}

@Override
public void removeView(View view){
  mGlobal.removeView(view,false);
}

可以看到,WindowManagerImpl並沒有直接實現Window的三大操作,而是全部交給了WindowManagerGlobal來處理,WindowManagerGlobal以工廠的形式向外提供自己的實例。WindowManagerGlobal的addView方法主要分為如下幾步:

  • 檢查參數是否合法,如果是子Window那么還需要調整一些布局參數
  • 創建ViewRootImpl並將View添加到列表中
  • 通過ViewRootImpl來更新界面並完成Window的添加過程

Window的刪除過程

Window的刪除過程和添加過程一樣,都是先通過WindowManagerImpl后,在進一步通WindowManagerGlobal來實現的。里面用到一個dispatchDetachedFromWindow方法內部實現,這個方法主要做了四件事:

  • 垃圾回收相關的工作,比如清除數據和消息、移除回調
  • 通過Session的remove方法刪除Window
  • 調用View的dispatchDetachedFromWindow方法,在內部會調用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()
  • 調用WindowManagerGlobal的doRemoveView方法刷新數據

Window的更新過程

主要是用到updateViewLayout方法,首先它需要更新View的LayoutParams並替換掉老的LayoutParams,接着再更新ViewRootImpl中的LayoutParams,這一步是通過ViewRootImpl的setLayoutParams方法來實現的。在ViewRootImpl中會通過scheduleTraversals方法對View進行重新布局,包括測量、布局、重繪這三個過程。

Window的創建過程

View是Android中的視圖呈現方式,但是View不能單獨存在,它必須附着在Window這個抽象的概念上面,因此有視圖的地方就有Window。

Activity的Window創建過程

如何創建,需要了解Activity啟動過程,比較復雜,但它最終由ActivityThred中的perfromLaunchActivity()來完成整個啟動過程,在這個方法內部會通過類加載器創建Activity的實例對象,並調用其attach方法為其關聯運行過程中所依賴的一系列上下文環境變量。

在Activity的attach方法里,系統會創建Activity所屬的Window對象並為其設置回調接口,Window對象的創建是通過PolicyManager的makeNewWindow方法實現的,對於Activity的setContentView的實現可以看出,Activity將具體實現交給了Window處理,而Window的具體實現是PhoneWindow,所以只需要看PhoneWindow相關邏輯即可,大致以下幾個步驟:

  • 如果沒有DecorView,那么就創建它。DecorView是一個FrameLayout,是Activity的頂級View,一般來說它的內部包含標題欄和內部欄。
  • 將View添加到DecorView的mContentParent中。
  • 回調Activity的onContentChanged方法通知Activity視圖已經發生改變。Activity的onContentChanged是一個空實現。

經過上面三個步驟,DecorView已經被創建初始化完畢,Activity的布局文件已經成功添加到了DecorView的mContentParent中,但是這個時候DecorView還沒有被WindowManager正式添加到Window中,真正被視圖調用是在Activity的onResume方法,接着會調用Activity的makeVisible(),正是在makeVisible方法中,DecorView真正地完成了添加和顯示這兩個過程。

Dialog的Window創建過程

Dialog的Window的創建過程和Activity類似,有以下幾個步驟:

  • 創建Window。同樣是通過PolicyManager的makeNewWindow方法來完成的。
  • 初始化DecorView並將Dialog的視圖添加到DecorView中。
  • 將DecorView添加到Window中並顯示。在Dialog的show方法中,會通過WindowManager將DecorView添加到Window中。

普通的Dialog有一個特殊之處,那就是必須采用Activity的Context,如果采用Application的Context,就會報錯。

Toast的Window創建過程

Toast和Dialog不同,它的工作過程稍微復雜。首先Toast也是基於Window來實現的,但是由於Toast具有定時取消這一功能,所以系統采用了Handler。在Toast的內部有兩類的IPC過程,第一類是Toast訪問NotificationManagerService,第二類是NotificationManagerService回調Toast的TN接口。

Toast屬於系統Window,它內部的視圖有兩種方式指定,一種是系統默認的樣式,另一種是通過setView方法來指定一個自定義View,不管如何,它們都對應Toast的一個View類型的內部成員mNextView。Toast提供了show和cancel分別用於顯示和隱藏Toast,它們的內部是一個IPC過程。

閱讀擴展

源於對掌握的Android開發基礎點進行整理,羅列下已經總結的文章,從中可以看到技術積累的過程。
1,Android系統簡介
2,ProGuard代碼混淆
3,講講Handler+Looper+MessageQueue關系
4,Android圖片加載庫理解
5,談談Android運行時權限理解
6,EventBus初理解
7,Android 常見工具類
8,對於Fragment的一些理解
9,Android 四大組件之 " Activity "
10,Android 四大組件之" Service "
11,Android 四大組件之“ BroadcastReceiver "
12,Android 四大組件之" ContentProvider "
13,講講 Android 事件攔截機制
14,Android 動畫的理解
15,Android 生命周期和啟動模式
16,Android IPC 機制
17,View 的事件體系
18,View 的工作原理
19,理解 Window 和 WindowManager
20,Activity 啟動過程分析
21,Service 啟動過程分析
22,Android 性能優化
23,Android 消息機制
24,Android Bitmap相關
25,Android 線程和線程池
26,Android 中的 Drawable 和動畫
27,RecylerView 中的裝飾者模式
28,Android 觸摸事件機制
29,Android 事件機制應用
30,Cordova 框架的一些理解
31,有關 Android 插件化思考
32,開發人員必備技能——單元測試


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM