Android開發(fā)八《理解Window和WindowManager》

一、Window和WindowManager

Window:

Window是一個抽象類,它定義了頂級窗體樣式和行為。其唯一的實現類是PhoneWindow。
每個Window都對應一個View和一個ViewRootImpl,Window和View通過ViewRootImpl來建立聯系。Window并不可見,它實際以View的形式存在,它是View的直接管理者。

WindowManager:

實際使用中無法訪問Window,對Window的訪問必須通過WindowManager,對Window的操作通過它完成。Window的具體實現位于WindowManagerService中,WindowManager和WindowManagerService的交互是一個IPC過程。

聯系

使用WindowManager添加一個Window

//將一個Button添加到屏幕為(100,300)的位置
mFloatingButton = new Button(this);
mFloatingButton.setText("test button");

mLayoutParams = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,PixelFormat.TRANSPARENT);
//第三個參數代表flags,第四個參數代表type

mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
        | LayoutParams.FLAG_NOT_FOCUSABLE
        | LayoutParams.FLAG_SHOW_WHEN_LOCKED;//配置flags
mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;//配置type
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;//配置gravity
mLayoutParams.x = 100;//相對于gravity
mLayoutParams.y = 300;//相對于gravity

mFloatingButton.setOnTouchListener(this);
mWindowManager.addView(mFloatingButton, mLayoutParams);

WindowManager的三個重要參數:
最主要設置WindowManager.LayoutParams構造函數中的

  1. flags:
    表示Window的屬性。主要的可選值含義:
屬性值 描述
FLAG_NOT_FOCUSABLE 表示Window不需要獲取焦點,也不需要接收各種輸入事件,此標記會同時啟動FLAG_NOT_TOUCH_MODEL,最終事件會傳遞給下層的具有焦點的Window。
FLAG_NOT_TOUCH_MODAL 表示系統(tǒng)會將當前Window區(qū)域以外的單擊事件傳遞給底層的Window,而區(qū)域以內的單擊事件則自己處理。一般都需要開啟此標記,否則其他Window將無法收到單擊事件。
FLAG_SHOW_WHEN_LOCKED 表示Window可顯示在鎖屏界面。
  1. type:
    表示Window的類型。Window有三種類型:
Window 層級 描述
應用Window 1~99 對應一個Activity
子Window 1000~1999 不能單獨存在,需附屬特定的父Window。如Dialog。
系統(tǒng)Window 2000~2999 需申明權限(SYSTEM_ALERT_WINDOW)才能創(chuàng)建。如Toast。

注意:
Window是分層的,層級大的會覆蓋在層級小的Window上面。
對應WindowManager.LayoutParams的type參數。

  1. gravity
    表示Window的位置。
    默認是屏幕中間。
    x、y值相對于gravity。

二、Window的內部機制

WindowManager對Window主要有三大操作:添加、更新和刪除。這三個方法主要是定義在ViewManager接口中:

public interface ViewManager{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

WindowManager也是一個接口,它繼承了ViewManager接口:

public interface WindowManager extends ViewManager {}

WindowManager的具體實現類是WindowManagerImpl

public final class WindowManagerImpl implements WindowManager{
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

        @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()、updateViewLayout()、removeView()實現WindowManager對Window的添加、刪除和修改。

下面分別來看WindowManagerGlobal對Window操作的大致過程:

  1. Window的添加過程:


    添加過程
  2. Window的刪除過程


    刪除過程
  3. Window的更新過程


    更新過程

Windows的三大操作最終都會通過一個IPC過程移交給WindowManagerService。
Window和View通過ViewRootImpl來聯系,ViewRootImpl可控制View的測量、布局和重繪。

三、Window的創(chuàng)建過程

View 是 Android 中的視圖的呈現方式,但是 View 不能單獨存在,它必須附著在 Window 這個抽象的概念上面,Activity、Dialog、Toast 等視圖都對應著一個 Window。

1、Activity的創(chuàng)建過程

Activity的創(chuàng)建過程

2、Dialog的創(chuàng)建過程

  1. 創(chuàng)建WindowDialog。和Activity類似,同樣是通過PolicyManager.makeNewWindow()來實現。
  2. 初始化DecorView并將Dialog的視圖添加到DecorView中去。和Activity類似,同樣是通過Window.setContentView()來實現。
  3. 將DecorView添加到Window中顯示。和Activity一樣,都是在自身要出現在前臺時才會將添加Window。
  4. Dialog.show()方法:完成DecorView的顯示。
  5. Dialog.dismiss()方法:完成移除View,調用WindowManager.remoteViewImmediate()方法;

3、Toast的創(chuàng)建過程

  1. Toast的內部的視圖由兩種方式指定:
  1. Toast具有定時取消功能,故系統(tǒng)采用Handler做定時處理。
  2. 在Toast內部有兩類IPC過程:
  • Toast訪問NotificationManagerService(NMS);
  • NotificationManagerService回調Toast里的TN接口。
  1. Toast提供方法show()cancel()分別用于顯示和隱藏Toast。
  • Toast的顯示和隱藏都需要通過NMS來實現,由于NMS運行在系統(tǒng)進程中,故需通過遠程調用的方式來進行顯示和隱藏Toast。
  • NMS處理Toast的顯示和隱藏請求時會跨進程回調TN中的方法,由于TN運行在Binder線程池中,故需通過Handler將其切換到當前線程(發(fā)送Toast請求的線程)。

NMS只是起到了管理Toast隊列及其延時的效果,Toast 的顯示和隱藏實際是通過TN來實現的。

Toast的創(chuàng)建過程

參考:(開發(fā)藝術之Window)[http://www.itdecent.cn/p/ed03aed9a4db]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容