Android Window相關(guān)知識點簡述

前言:有時候會好奇怒医,打開一個應(yīng)用你所看到的屏幕上每一個界面時怎么顯現(xiàn)出來的咆爽。

下面就會在這個問題進行剖析之前球拦,做一些知識儲備。

1.在完成這個問題之前需要熟悉一下幾個知識點续搀。


  • Window

  • WindowManager

  • WindowManagerService

  • DecorView

  • PhoneWindow

  • RootViewimpl

  • ViewManager

當(dāng)看到這些的時候塞琼,會想這些是什么玩意全是什么什么window,下面就會對這些進行闡釋禁舷。對這些知識點熟悉后彪杉,就能很容易的理解android的Activity是怎么顯示和加載的了。

2.所分析的源碼是基于Android6.0


Window:就如英文所表示的意思牵咙,它在Android中表示一個窗口并且它是一個用來裝View的抽象概念派近。它可以提供一些背景,標(biāo)題等功能洁桌。幾乎所有的View都是附屬在Window上面的(PopWindow就沒有所依附的Window渴丸,它是直接浮在Window上面的一個容器)。

WindowManager:在Window中有個setWindowManager方法另凌,該方法是為window添加一個window管理器谱轨,一個Window對應(yīng)于一個WindowManager,它繼承與ViewManager接口吠谢,接口中定義了三個方法add, updateViewLayout, removeView.所以WindowManger想對Window中的View進行操作的話土童,是必須利用WindowManager的

WindowManagerService:它是由SystemServer孵化出來的一個Service.它繼承于IWindowManager.Stub,馬上反應(yīng)出就知道它需要進程間通信的工坊。它通信的主要目標(biāo)就還是WindowManager献汗。所以它的作用就是對屏幕里面的窗口進行一一管理。

PhoneWindow:它是Window的唯一實現(xiàn)類王污。它里面包含了一個最頂層的DecorView罢吃。大家使用的View都是存在于DecorView下面的。PhoneWindow里面繼承了一個Callback接口玉掸,該接口里面包含了大量事件處理方法刃麸。分析的點擊事件,就是對這些方法進行分析的司浪。

RootViewImpl:View的測量泊业,布局,繪制就是在它的performTraversals方法里開始的啊易。

以上只是對一些重要的知識點進行一個簡單闡釋吁伺,下面將會從代碼來閱讀每個關(guān)鍵點,最后再給出Android是怎么加載并顯示一個Activity的租谈。

3.源碼閱讀


Window:就如英文所表示的意思篮奄,它在Android中表示一個窗口并且它是一個用來裝View的抽象概念捆愁。它可以提供一些背景,標(biāo)題等功能窟却。幾乎所有的View都是附屬在Window上面的(PopWindow就沒有所依附的Window昼丑,它是直接浮在Window上面的一個容器)。

public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
           setWindowManager(wm, appToken, appName, false);
          }

/**

* Set the window manager for use by this Window to, for example,

* display panels.  This is not used for displaying the

* Window itself -- that must be done by the client.

*

* @param wm The window manager for adding new windows.

*/

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,

boolean hardwareAccelerated) {

mAppToken = appToken;

mAppName = appName;

mHardwareAccelerated = hardwareAccelerated

|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);

if (wm == null) {

wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);

}

mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

}

雖然有兩個setWindowManager 方法來為Window添加WindowManager夸赫,但可以直接看后者菩帝。這里可以看到WindowManager的是一個實現(xiàn)類是WindowManagerImpl.從這里就可以進入到WindowManager去看看它的代碼了。

WindowManager是一個接口繼承于ViewManager接口茬腿。在ViewManager中有三個方法分別是
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
這三個方法就說明了前面為什么說WindowManager是外界對Window訪問的接口了呼奢,你想操作Window中View就需要通過WindowManager來進行添加,更新好布局參數(shù)切平,移除Window中的View握础。

WindowManager中LayoutParams對ViewGroup的LayoutParams進行了一個補充給對應(yīng)的Window添加Type參數(shù)表示W(wǎng)indow的類型,有三種類型悴品,分別是應(yīng)用Window禀综,子Window和系統(tǒng)Window,應(yīng)用類Window對應(yīng)一個Activity他匪,子Window不能單獨存在菇存,它需要附屬在特定的父Window之中,比如常見的Dialog就是一個子Window邦蜜,系統(tǒng)Window是需要聲明權(quán)限在能創(chuàng)建的Window依鸥,比如Toast和系統(tǒng)狀態(tài)欄這些都是系統(tǒng)Window。
對Type類型的定義截取一段:
/**
* Start of window types that represent normal application windows.
*/
public static final int FIRST_APPLICATION_WINDOW = 1;

/**
  * End of types of application windows.
  */
public static final int LAST_APPLICATION_WINDOW = 99;

這兩個說明了應(yīng)用層Window數(shù)值大小是1至99

/**
* Start of types of sub-windows.  The {@link #token} of these windows
* must be set to the window they are attached to.  These types of
* windows are kept next to their attached window in Z-order, and their
* coordinate space is relative to their attached window.
*/
public static final int FIRST_SUB_WINDOW = 1000;
/**
* End of types of sub-windows.
 */
 public static final int LAST_SUB_WINDOW = 1999;

這兩個說明了子Window數(shù)值大小是1000至1999

/**
* Start of system-specific window types.  These are not normally
* created by applications.
*/
    public static final int FIRST_SYSTEM_WINDOW     = 2000;

/**
  * End of types of system windows.
  */
    public static final int LAST_SYSTEM_WINDOW      = 2999;

這兩個說明了系統(tǒng)Window數(shù)值大小是 2000至2999

通過Type的設(shè)置可以改變Window所處層級悼沈,也就指定了View顯示的優(yōu)先級贱迟。
WindowManager的實現(xiàn)類是WindowManagerImpl,在它里面主要是去看對View操作的三個方法:add update remove

@Override'
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        android.util.SeempLog.record_vg_layout(383,params);
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
WindowManagerimpl的add方法實際上是調(diào)用了WindowManagerGlobal的add方法,方法如下:
public void addView(View view, ViewGroup.LayoutParams params,
         Display display, Window parentWindow) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (display == null) {
        throw new IllegalArgumentException("display must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if (parentWindow != null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } else {
        // If there's no parent, then hardware acceleration for this view is
        // set from the application's hardware acceleration setting.
        final Context context = view.getContext();
        if (context != null
                && (context.getApplicationInfo().flags
                        & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }

    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        // Start watching for system property changes.
        if (mSystemPropertyUpdater == null) {
            mSystemPropertyUpdater = new Runnable() {
                @Override public void run() {
                    synchronized (mLock) {
                        for (int i = mRoots.size() - 1; i >= 0; --i) {
                            mRoots.get(i).loadSystemProperties();
                        }
                    }
                }
            };
            SystemProperties.addChangeCallback(mSystemPropertyUpdater);
        }

        int index = findViewLocked(view, false);
        if (index >= 0) {
            if (mDyingViews.contains(view)) {
                // Don't wait for MSG_DIE to make it's way through root's queue.
                mRoots.get(index).doDie();
            } else {
                throw new IllegalStateException("View " + view
                        + " has already been added to the window manager.");
            }
            // The previous removeView() had not completed executing. Now it has.
        }

        // If this is a panel window, then find the window it is being
        // attached to for future reference.
        if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
            final int count = mViews.size();
            for (int i = 0; i < count; i++) {
                if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                    panelParentView = mViews.get(i);
                }
            }
        }
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }

    // do this last because it fires off messages to start doing things
    try {
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        // BadTokenException or InvalidDisplayException, clean up.
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
        throw e;
    }
}
從這個方法中可以提煉出幾個關(guān)鍵點絮供,

1.ViewRootImpl 在它里面開始對Window所加載的View進行繪制
2.mView mRoots mParms為數(shù)組衣吠,它們之間形成一一對應(yīng)的關(guān)系
3.display: 提供有關(guān)邏輯顯示器大小和密度的信息
對ViewRootImpl放到以后的文章中進行詳解,它對于理解自定義View有很大的幫助壤靶。

PhoneWindow:大部分View都有它本身所依附的Window缚俏,而PhoneWindow是Window的唯一實現(xiàn)類,所以可以直接說大部分View都是依附在PhoneWindow上贮乳。
PhoneWinodw中有個關(guān)鍵的DecotView變量忧换。
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
從它的注釋就可以知道,它是界面顯示View中的頂層View向拆,而我們所操作看到和操作的View都是它的子View亚茬。DecorView本身是繼承于FrameLayout。它內(nèi)部有兩個變量
// View added at runtime to draw under the status bar area
private View mStatusGuard;
// View added at runtime to draw under the navigation bar area
private View mNavigationGuard;
注釋說明它們兩個在DecorView的頂部和底部的指示欄浓恳,中間就由ViewGroup呈現(xiàn)的Content區(qū)域刹缝。
所以Activit碗暗,PhoneWindow,DecorView梢夯,View的關(guān)系可以用如下圖來說明:


2017021702426993.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末言疗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子厨疙,更是在濱河造成了極大的恐慌洲守,老刑警劉巖疑务,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沾凄,死亡現(xiàn)場離奇詭異,居然都是意外死亡知允,警方通過查閱死者的電腦和手機撒蟀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來温鸽,“玉大人保屯,你說我怎么就攤上這事〉拥妫” “怎么了姑尺?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝠猬。 經(jīng)常有香客問我切蟋,道長,這世上最難降的妖魔是什么榆芦? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任柄粹,我火速辦了婚禮,結(jié)果婚禮上匆绣,老公的妹妹穿的比我還像新娘驻右。我一直安慰自己,他們只是感情好崎淳,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布堪夭。 她就那樣靜靜地躺著,像睡著了一般拣凹。 火紅的嫁衣襯著肌膚如雪森爽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天咐鹤,我揣著相機與錄音拗秘,去河邊找鬼。 笑死祈惶,一個胖子當(dāng)著我的面吹牛雕旨,可吹牛的內(nèi)容都是我干的扮匠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凡涩,長吁一口氣:“原來是場噩夢啊……” “哼棒搜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起活箕,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤力麸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后育韩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體克蚂,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年筋讨,在試婚紗的時候發(fā)現(xiàn)自己被綠了埃叭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡悉罕,死狀恐怖赤屋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情壁袄,我是刑警寧澤类早,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站嗜逻,受9級特大地震影響涩僻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜变泄,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一令哟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妨蛹,春花似錦屏富、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颤难,卻和暖如春神年,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背行嗤。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工已日, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人栅屏。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓飘千,卻偏偏與公主長得像堂鲜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子护奈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容