要點提煉|開發藝術之Window

多數狀況咱們是和ActivityView打交道,在以前學習中也都接觸過,本篇來深刻學習和它們有緊密聯繫的Window,主要內容:

  • Window&WindowManager
  • Window的內部機制(添加、刪除、更新)
  • Window的建立過程(Activity、Dialog、Toast)

1.Window&WindowManagerbash

a.Window&PhoneWindow: Window是一個抽象類,它定義了頂級窗體樣式和行爲。其惟一的實現類是PhoneWindowide

推薦閱讀Window,PhoneWindow,DecorView,setContentView源碼理解佈局

b.Window&View: 每一個Window都對應一個View和一個ViewRootImpl,Window和View經過ViewRootImpl來創建聯繫。Window並不可見,它實際以View的形式存在,它是View的直接管理者post

c.Window&WindowManager: 實際使用中沒法訪問Window,對Window的訪問必須經過WindowManager,對Window的操做經過它完成。學習

  • 例如:經過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的三個重要參數:ui

  • flags:表示Window的屬性。主要的可選值含義:
    • FLAG_NOT_FOCUSABLE:表示Window不須要獲取焦點,也不須要接收各類輸入事件,此標記會同時啓動FLAG_NOT_TOUCH_MODEL,最終事件會傳遞給下層的具備焦點的Window。
    • FLAG_NOT_TOUCH_MODAL:表示系統會將當前Window區域之外的單擊事件傳遞給底層的Window,而區域之內的單擊事件則本身處理。通常都須要開啓此標記,不然其餘Window將沒法收到單擊事件。
    • FLAG_SHOW_WHEN_LOCKED:表示Window可顯示在鎖屏界面。
  • type:表示Window的類型。Window有三種類型:
    • 應用Window:對應一個Activity。
    • 子Window:不能單獨存在,需附屬特定的父Window。如Dialog。
    • 系統Window: 需申明權限才能建立。如Toast。
  • Window是分層的,見下表。
  • 層級大的會覆蓋在層級小的Window上面。
  • 對應WindowManager.LayoutParams的type參數。

image

  • gravity:表示Window的位置。
    • 默認是屏幕中間。
    • xy值相對於gravity。

d.WindowManager&WindowManagerService: Window的具體實現位於WindowManagerService中。WindowManager和WindowManagerService的交互是一個IPC(跨進程通訊)過程。this


2.Window的內部機制spa

  • 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{
        @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以單例模式向外提供本身的實例:
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
複製代碼

一幅圖說明這幾個類的關係:.net

image

所以,經過WindowManagerGlobal的addView()、updateViewLayout()、removeView()實現WindowManager對Window的添加、刪除和修改。線程

下面分別來看WindowManagerGlobal對Window操做的大體過程:

a.Window的添加過程:

image

b.Window的刪除過程

image

c.Window的更新過程

image

不難發現, 以上驗證了以前的總結:

  • Windows的三大操做最終都會經過一個IPC過程移交給WindowManagerService。
  • Window和View經過ViewRootImpl來聯繫,ViewRootImpl可控制View的測量、佈局和重繪。

推薦閱讀:源碼剖析之------Window的內部實現機制我眼中的Window建立/添加/刪除/更新過程


3.Window的建立過程

因爲View必須依附Window才能呈現出來,所以有View的地方必有Window。在Android中能夠提供View的地方有Activity、Dialog和Toast,下面分別來看以上三種Window的大體建立過程:

a.Activity的Window建立過程

image

推薦閱讀Activity的Window建立過程分析(源碼)

b.Dialog的Window建立過程

Step1:建立WindowDialog。和Activity相似,一樣是經過PolicyManager.makeNewWindow() 來實現。

Step2:初始化DecorView並將Dialog的視圖添加到DecorView中去。和Activity相似,一樣是經過Window.setContentView() 來實現。

Step3:將DecorView添加到Window中顯示。和Activity同樣,都是在自身要出如今前臺時纔會將添加Window。

  • Dialog.show() 方法:完成DecorView的顯示。
  • WindowManager.remoteViewImmediate() 方法:當Dialog被dismiss時移除DecorView。

c.Toast的Window建立過程

①Toast的內部的視圖由兩種方式指定:

  • 系統默認的樣式;
  • 經過setView()指定一個自定義View。

這裏見技能篇之Toast的使用

②Toast具備定時取消功能,故系統採用Handler作定時處理。

③在Toast內部有兩類IPC過程:

  • Toast訪問NotificationManagerService(NMS);
  • NotificationManagerService回調Toast裏的TN接口。

④Toast提供方法show()cancel() 分別用於顯示和隱藏Toast。

  • Toast的顯示和隱藏都須要經過NMS來實現,因爲NMS運行在系統進程中,故需經過遠程調用的方式來進行顯示和隱藏Toast。
  • NMS處理Toast的顯示和隱藏請求時會跨進程回調TN中的方法,因爲TN運行在Binder線程池中,故需經過Handler將其切換到當前線程(發送Toast請求的線程)。

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

image

推薦閱讀:Android對話框Dialog,PopupWindow,Toast的實現機制


但願這篇文章對你有幫助~

相關文章
相關標籤/搜索