Andoird WindowManager管理Window的流程

前言

分析Windowmanager如何管理window的流程盗温。

一 Window基礎(chǔ)

添加遣蚀、更新湃窍、刪除一個Window:

Button mButton = new Button(this);
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
        ViewGroup.LayoutParams.WRAP_CONTENT,0,0, PixelFormat.TRANSPARENT);
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mLayoutParams.x = 10;
mLayoutParams.y = 11;
//add
windowManager.addView(mButton,mLayoutParams);
//update
mLayoutParams.x = 100;
windowManager.updateViewLayout(mButton,mLayoutParams);
//remove
windowManager.removeView(mButton);

參數(shù)說明:
1提岔、flag,控制Window的顯示特性拆座,參數(shù)很多可自行查詢API,常用如下
FLAG_NOT_TOUCH_MODAL:Window區(qū)域內(nèi)的點(diǎn)擊事件自己處理主巍,之外的傳遞給底層Window,通常打開此標(biāo)記
FLAG_NOT_FOCUSALE:不需要焦點(diǎn),直接傳遞到底層Window
FLAG_SHOW_WHEN_LOCKED:顧名思義挪凑,顯示在鎖屏上
2孕索、type,三種類型。Window是分層的
應(yīng)用Window:層級1-99躏碳,對應(yīng)一個activity
子Window:層級1000-1999,需要在特定的父Window中搞旭,比如Dialog
系統(tǒng)Window:層級2000-2999,需添加權(quán)限SYSTEM_ALERT_WINDOW,比如狀態(tài)欄

二 過程分析

2.1 添加過程

ViewManager只是個interface,搜索源碼菇绵,實(shí)現(xiàn)類為WindowManagerImpl

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

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

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

然后交給代理類mGlobal即WindowManagerGlobal

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
    ...
    root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
    ...
    try {
            root.setView(view, wparams, panelParentView);
        } 
    ...
}

mViews肄渗,mRoots,mParams是三個ArrayList咬最,用來保存所有window對應(yīng)的view翎嫡、ViewRootImpl和布局參數(shù)
ViewRootImpl:WindowManager創(chuàng)建它來管理view
最后通過ViewRootImpl.setView來設(shè)置view

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    ...
    try {
         mOrigWindowType = mWindowAttributes.type;
         mAttachInfo.mRecomputeGlobalAttributes = true;
         collectViewAttributes();
         res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                 getHostVisibility(), mDisplay.getDisplayId(),
                    mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                      mAttachInfo.mOutsets, mInputChannel);
    }
    ...

然后是mWindowSession.addToDisplay,其實(shí)現(xiàn)是Session.addToDisplay

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }

所以其實(shí)是WindowManagerService的addWindow永乌,這里addWindow就是WindowManagerService把window如何布置到屏幕上的具體深入細(xì)節(jié)了惑申,就不跟了。

2.2 刪除過程

WindowManagerGlobal的removeView調(diào)用

removeViewLocked(index, immediate);

private void removeViewLocked(int index, boolean immediate) {
        ViewRootImpl root = mRoots.get(index);
        View view = root.getView();

        if (view != null) {
            InputMethodManager imm = InputMethodManager.getInstance();
            if (imm != null) {
                imm.windowDismissed(mViews.get(index).getWindowToken());
            }
        }
        boolean deferred = root.die(immediate);
        if (view != null) {
            view.assignParent(null);
            if (deferred) {
                mDyingViews.add(view);
            }
        }
    }

ViewRootImpl.die

boolean die(boolean immediate) {
        if (DEBUG_LIFECYCLE) {
            Log.v(mTag, "die: immediate = " + immediate + ", mIsInTraversal = " + mIsInTraversal
                    + ",mIsDrawing = " + mIsDrawing + ",this = " + this);
        }

        // Make sure we do execute immediately if we are in the middle of a traversal or the damage
        // done by dispatchDetachedFromWindow will cause havoc on return.
        if (immediate && !mIsInTraversal) {
            doDie();
            return false;
        }

        if (!mIsDrawing) {
            destroyHardwareRenderer();
        } else {
            Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
                    "  window=" + this + ", title=" + mWindowAttributes.getTitle());
        }
        mHandler.sendEmptyMessage(MSG_DIE);
        return true;
    }

mHandler.sendEmptyMessage(MSG_DIE);延時調(diào)用翅雏,最終還是會直接調(diào)用doDie();

void doDie() {
    ...
    if (mAdded) {
        dispatchDetachedFromWindow();
    }
    ...
    WindowManagerGlobal.getInstance().doRemoveView(this);
    ...
}

doRemoveView硝桩,刷新mViews,mRoots枚荣,mParams數(shù)據(jù)
dispatchDetachedFromWindow中主要行為三點(diǎn):

void dispatchDetachedFromWindow() {
        if (mView != null && mView.mAttachInfo != null) {
            mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
        //調(diào)用view的dispatchDetachedFromWindow碗脊,資源回收,中止動畫線程
            mView.dispatchDetachedFromWindow();
        }

        mAccessibilityInteractionConnectionManager.ensureNoConnection();
        mAccessibilityManager.removeAccessibilityStateChangeListener(
                mAccessibilityInteractionConnectionManager);
        mAccessibilityManager.removeHighTextContrastStateChangeListener(
                mHighContrastTextManager);
        removeSendWindowContentChangedCallback();

        destroyHardwareRenderer();
    //垃圾回收橄妆,清空衙伶,設(shè)為null
        setAccessibilityFocus(null, null);

        mView.assignParent(null);
        mView = null;
        mAttachInfo.mRootView = null;

        mSurface.release();

        if (mInputQueueCallback != null && mInputQueue != null) {
            mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
            mInputQueue.dispose();
            mInputQueueCallback = null;
            mInputQueue = null;
        }
        if (mInputEventReceiver != null) {
            mInputEventReceiver.dispose();
            mInputEventReceiver = null;
        }
        try {
        //Session,IPC調(diào)用害碾,最后調(diào)用到WindowManagerService的removeWindow矢劲,類似addview
            mWindowSession.remove(mWindow);
        } catch (RemoteException e) {
            Log.e(mTag, "RemoteException remove window " + mWindow + " in " + this, e);
        }

        // Dispose the input channel after removing the window so the Window Manager
        // doesn't interpret the input channel being closed as an abnormal termination.
        if (mInputChannel != null) {
            mInputChannel.dispose();
            mInputChannel = null;
        }
    //
        mDisplayManager.unregisterDisplayListener(mDisplayListener);

        unscheduleTraversals();
    }

跟新過程

WindowManagerGlobal的updateViewLayout

public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

        view.setLayoutParams(wparams);

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams);
            root.setLayoutParams(wparams, false);
        }
    }

ViewRootImpl.setLayoutParams刷新LayoutParams

void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
    ...
    //重新布局,包含測量慌随,布局芬沉,重繪
    scheduleTraversals();
    ...
}
然后看scheduleTraversals躺同,其中有一句
```javascript
mHandler.post(mTraversalRunnable);

mTraversalRunnable調(diào)用performTraversals,這個就是所有view的繪制過程了丸逸,重繪時會調(diào)用relayoutWindow然后調(diào)用mWindowSession.relayout蹋艺,即WindowManagerService的relayoutWindow方法

總結(jié)

Windowmanager通過ViewRootImpl來添加、更新和刪除window,最終的實(shí)現(xiàn)都是WindowmanagerService具體實(shí)現(xiàn)黄刚。本文目的也是掌握Windowmanager管理window的流程捎谨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市憔维,隨后出現(xiàn)的幾起案子涛救,更是在濱河造成了極大的恐慌,老刑警劉巖业扒,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件检吆,死亡現(xiàn)場離奇詭異,居然都是意外死亡程储,警方通過查閱死者的電腦和手機(jī)咧栗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虱肄,“玉大人,你說我怎么就攤上這事交煞∮搅” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵素征,是天一觀的道長集嵌。 經(jīng)常有香客問我,道長御毅,這世上最難降的妖魔是什么根欧? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮端蛆,結(jié)果婚禮上凤粗,老公的妹妹穿的比我還像新娘。我一直安慰自己今豆,他們只是感情好嫌拣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呆躲,像睡著了一般异逐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上插掂,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天灰瞻,我揣著相機(jī)與錄音腥例,去河邊找鬼。 笑死酝润,一個胖子當(dāng)著我的面吹牛燎竖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播袍祖,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼底瓣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蕉陋?” 一聲冷哼從身側(cè)響起捐凭,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凳鬓,沒想到半個月后茁肠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缩举,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年垦梆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仅孩。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡托猩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辽慕,到底是詐尸還是另有隱情京腥,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布溅蛉,位于F島的核電站公浪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏船侧。R本人自食惡果不足惜欠气,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望镜撩。 院中可真熱鬧预柒,春花似錦、人聲如沸袁梗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽围段。三九已至顾翼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奈泪,已是汗流浹背适贸。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工灸芳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拜姿。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓烙样,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蕊肥。 傳聞我的和親對象是個殘疾皇子谒获,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

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

  • 一、理解 Android 的 Window Window 表示一個窗口的概念壁却,是一個抽象的概念批狱,每一個 Windo...
    任教主來也閱讀 6,360評論 3 21
  • Window是一個抽象類,它的具體實(shí)現(xiàn)是PhoneWindow展东。創(chuàng)建一個Window是很簡單的事赔硫,只需要通過Win...
    小柏不是大白閱讀 1,180評論 0 0
  • Window 表示一個窗口的概念,是一個抽象類盐肃,它的具體實(shí)現(xiàn)是 PhoneWindow爪膊。 8.1 Window 和...
    kongjn閱讀 1,470評論 0 3
  • 不再討厭秋天的寒冷,因?yàn)槲乙呀?jīng)足夠強(qiáng)大砸王。不再殷切的期待候鳥的歸來推盛,因?yàn)槲乙呀?jīng)把等候的心情消磨殆盡。我開始蓄起胡子谦铃,...
    落桑Chen閱讀 271評論 4 15
  • 1. 周末慵懶的午后荷辕,我一如既往地走進(jìn)這家街角的咖啡館,撲鼻而來的依舊是濃郁的咖啡香氣件豌,還有剛出爐的可頌獨(dú)有的酥油...
    2ce380ee770b閱讀 131評論 0 0