進階之路 | 奇妙的Window之旅

前言

本文已經收錄到個人Github我的博客,歡迎大佬們光臨寒舍:java

個人GIthub博客android

學習清單:

  • Window&WindowManagerServicegit

  • Window&WindowManagergithub

  • Window&PhoneWindowsegmentfault

  • Window&Activityapp

  • Window&Viewide

  • Window內部機制函數

  • Window建立過程佈局

一.爲何要學習Window?

Android手機上全部的視圖都是經過Window來呈現的,像經常使用的ActivityDialogPopupWindowToast,他們的視圖都是附加在Window上的,因此能夠這麼說 ——「Window是View的直接管理者」。post

Window是一個頂層窗口查看和行爲的一個抽象基類,這個類的實例做爲一個頂級View添加到Window Manager。它提供了一套標準的UI方法,好比添加背景,標題等等。

Window自己很抽象,深刻了解Window,不只有助於你瞭解Android系統中各個層級之間的關係,還能夠對Toast的內部機制、自定義等等方面會有更加深刻的體會。

Window

二.核心知識點概括

2.1 Window關係解析

看到下面這張大圖,是否是感受有點亂亂的,別急,別急,心急吃不了熱豆腐,筆者將向您娓娓道來

Window總體關係圖

2.1.1 Window&PhoneWindow

筆者以前在進階之路 | 奇妙的View之旅中,說起setContentView的時候簡單說到了WindowPhoneWindow,相信看過的讀者已經對此有一個簡單的印象。

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

Activity的構成

2.1.2 Window&View

筆者以前在進階之路 | 奇妙的View之旅中,說起View工做流程的時候簡單說到了ViewRootImpl,相信看過的讀者已經對此有一個簡單的印象。

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

2.1.3 Window&WindowManagerService

想了解IPC的讀者,能夠看下筆者寫的一篇博客: 進階之路 | 奇妙的 IPC 之旅

Window的具體實現位於WindowManagerService中。WindowManagerWindowManagerService的交互是一個IPC(跨進程通訊)過程。

2.1.4 Window&WindowManager

實際使用中沒法訪問Window,對Window的訪問必須經過WindowManager(換句話說,WindowManager是外界訪問Window的入口),對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的三個重要參數:

  • 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有三種類型:

    A.應用類Window:對應一個Activity

    B.子Window:不能單獨存在,需附屬特定的父Window。如Dialog

    C.系統Window: 需聲明權限才能建立。如Toast

    • 系統權限有不少值,通常選用:TYPE_SYSTEM_OVERLAY/TYPE_SYSTEM_ERROR

    • 記得聲明權限:< uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>,Android6.0如下直接聲明權限便可,Android6.0以上還須要用戶打開軟件設置頁手動打開,才能受權。

  • Window是分層的,見下表
  • 層級大的會覆蓋在層級小的Window上面。
  • 對應WindowManager.LayoutParams的type參數。
Window 層級
應用Window 1-99
子Window 1000-1999
系統Window 2000-2999
  • gravity:表示Window的位置。
  • 默認是屏幕中間
  • xy值相對於gravity

2.2 Window的內部機制

  • WindowManagerWindow主要有三大操做:添加、更新和刪除

    這三個方法主要是定義在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的三大操做,而是交給了WindowManagerGlobalWindowManagerGlobal單例模式向外提供本身的實例:

WindowManagerImpl這種工做模式是典型的橋接模式

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
複製代碼

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

類的關係

所以,經過WindowManagerGlobaladdView()updateViewLayout()removeView()實現WindowManagerWindow的添加、刪除和修改。

2.2.1 Window的添加

Window添加流程

2.2.2 Window的刪除

Window刪除流程

2.2.3 Window的更新

Window的更新流程

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

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

限於篇幅,筆者這裏暫未貼上源碼,若是想了解的話,推薦一篇文章:我眼中的Window建立/添加/刪除/更新過程

2.3 Window的建立過程

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

2.3.1 ActivityWindow建立過程

Activity的啓動流程這裏不瞭解不要緊,筆者後面會專門寫一篇文章來介紹

Activity的Window建立過程

想了解ActivityWindow建立過程的源碼的讀者,筆者推薦一篇文章: Activity的Window建立過程分析

2.3.2 DialogWindow建立過程

Dialog的Window建立過程

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

2.3.3 ToastWindow建立過程

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

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

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

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

  • Toast訪問NotificationManagerService()(NotificationManagerService運行在系統的進程);
  • NotificationManagerService回調Toast裏的TN接口(運行在Binder線程池)。

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

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

Toast的Window建立流程

想了解ToastWindow建立過程的源碼的讀者,筆者推薦一篇文章:Android對話框Dialog,PopupWindow,Toast的實現機制

三.課堂小測試

恭喜你!已經看完了前面的文章,相信你對Window已經有必定深度的瞭解,下面,進行一下課堂小測試,驗證一下本身的學習成果吧!

Q1:一個應用中有多少個Window?

答案:無限個。緣由:任何一個View都是依附在Window上面,一個應用能夠有無限個View,天然Window也是無限個。

Q2:Window對象有存在的必要嗎

  • 疑惑點:Window能作的事情,View對象基本都能作:像觸摸事件、管理各個子View等等。
  • 可能有人會說:「WindowView的管理者」。
  • 追問:咱們知道,WindowManagerWindow的管理者,那爲何不直接用WindowManager管理View呢?
  • 答案:站在系統的角度上看,系統是「不知道」有View對象這個說法的!做爲系統,我有本身的驕傲,不去管你Window如何搬磚、如何砌牆,只給你地皮。而這時,Window爲了繪製出用戶想要的組件(按鈕、文字、輸入框等等),系統又不給我!沒事,那我本身定義,因而就定義了View機制,給每一個View提供Canvas,讓不一樣的View本身繪製具備本身特點的組件。同時,爲了更好的管理View,經過定義ViewGroup,等等。

Q3:Activity有存在的必要嗎?

  • 疑惑點:Window已是系統管理的窗口界面。那麼爲何還須要Activity呢?咱們把Activity所作的事情,所有封裝到Window不就行了?懸浮窗口Dialog中不就是沒有使用Activity來顯示一個懸浮窗嗎?
  • 答案:Android中的應用中,裏面對各個窗口的管理至關複雜(任務棧、狀態等等)。可是若是讓用戶本身去管理這些Window,先不說工做量,光讓用戶本身去實現任務棧這點,就很難了。爲了讓你們能簡單、快速的開發應用,AndroidActivity幫咱們管理好,咱們只需簡單的去重寫幾個回調函數,無需直接與Window對象接觸。

任何事物都有規律,語言再難,也是人發明的,同樣具備社會性,其實這幾個的關係就像是國家的中央系統的官員分配同樣,從古至今,一層對一層負責,這樣各司其職,又相互一層層聯繫着,達到效率最大化,忽然發現,古人的智慧仍是很厲害的,你讓皇帝(系統)去管轄全部的官員(view),豈不是要累死?因此纔出現了中間這些「官員」


若是文章對您有一點幫助的話,但願您能點一下贊,您的點贊,是我前進的動力

本文參考連接:

相關文章
相關標籤/搜索