Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(二)- Window 的添加過程

Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(一)

Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(三)- Activiy 的 Window 的創(chuàng)建過程

通過 Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(一) 已經(jīng)知道,我們能夠從 Activity 或者 Context 拿到的泛鸟,就是 WindowManager 的具體實(shí)現(xiàn) WindowManagerImpl营袜。
當(dāng)我們想要添加一個(gè) Window 的時(shí)候昙篙,就是要通過 WindowManagerImpl 的方法來實(shí)現(xiàn)茉继。更準(zhǔn)確的說翼闹,是 WindowManagerImpl 實(shí)現(xiàn)的 ViewManager 接口的方法丁寄。

public interface ViewManager
{
    /**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
     * errors, such as adding a second view to a window without removing the first view.
     * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
     * secondary {@link Display} and the specified display can't be found
     * (see {@link android.app.Presentation}).
     * @param view The view to be added to this window.
     * @param params The LayoutParams to assign to view.
     */
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

下面的例子是參考任玉剛的《Android 開發(fā)藝術(shù)探索》柑营,我做了一點(diǎn)修改屈雄。

        Button btn = new Button(this);
        btn.setText("WMS Demo");

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
                1, 0, PixelFormat.TRANSPARENT);
        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
        params.gravity = Gravity.LEFT | Gravity.TOP;
        params.x = 100;
        params.y = 100;
        getWindowManager().addView(btn, params);

其中,WindowManager.LayoutParams 的 type 和 flags 兩個(gè)參數(shù)比較重要官套,大家可以參考網(wǎng)上的各種說明酒奶。當(dāng)然蚁孔,源碼里面也有詳細(xì)的說明。
我這個(gè)例子惋嚎,是可以直接在 activity 里面跑起來的杠氢,作用是在屏幕上坐標(biāo)為 params.x = 100; params.y = 100; 的地方添加一個(gè)按鈕。

下面另伍,我們就跟著源碼看看修然,調(diào)用 getWindowManager().addView(btn, params) 后到底發(fā)生了什么。

Window 的添加過程

// WindowManagerImpl 
public final class WindowManagerImpl implements WindowManager {
    ...
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ...
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
    ...
}

可見质况,WindowManagerImpl 把任務(wù)轉(zhuǎn)給了 mGlobal 的 addView 方法愕宋。
看下面的代碼,再往下走结榄,就進(jìn)入了root.setView(view, wparams, panelParentView)中贝,也就是 ViewRootImpl 的方法。

// WindowManagerGlobal 
public final class WindowManagerGlobal {
    ...
    // 存儲(chǔ)所有 Window 對(duì)應(yīng)的 View
    private final ArrayList<View> mViews = new ArrayList<View>();
    // 存儲(chǔ)所有 Window 對(duì)應(yīng)的 ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    // 存儲(chǔ)所有 Window 對(duì)應(yīng)的布局參數(shù)
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    // 存儲(chǔ)正在被刪除的 View 對(duì)象臼朗,也就是調(diào)用了 removeView 方法邻寿,但是刪除操作還未完成的 View
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

    ...

    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");
        }

        ...

        ViewRootImpl root;
        View panelParentView = null;
        ...
            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;
        }
    }
}

ViewRootImpl 的 setView 會(huì)最終調(diào)用到 mWindowSession.addToDisplay()。

// ViewRootImpl 
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
    ...
    final IWindowSession mWindowSession;

    final W mWindow;
    ...
    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();

        mWindow = new W(this);
        ...
    }
    ...

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            ...
            int res; /* = WindowManagerImpl.ADD_OKAY; */

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
                ...
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
        }
    }
    ...
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            // scheduleTraversals 是 View 繪制的入口
            scheduleTraversals();
        }
    }

    ...

    static class W extends IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;

        W(ViewRootImpl viewAncestor) {
            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
            mWindowSession = viewAncestor.mWindowSession;
        }
        ...
    }
}

mWindowSession 的類型是 IWindowSession视哑,它是一個(gè) Binder 對(duì)象绣否,真正的實(shí)現(xiàn)類是 Session,這是一次 IPC 調(diào)用挡毅。
我在 Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(一) 中曾經(jīng)寫過蒜撮,WindowManagerService 是 IWindowManager 接口的實(shí)現(xiàn)。所以跪呈,這里才會(huì)和 WindowManagerService 發(fā)生關(guān)系段磨。

// WindowManagerGlobal
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }
// Session 
final class Session extends IWindowSession.Stub
                    implements IBinder.DeathRecipient {
    final WindowManagerService mService;
    ...
    public Session(WindowManagerService service, IWindowSessionCallback callback,
            IInputMethodClient client, IInputContext inputContext) {
        mService = service;
        ...
    }
    ...
    @Override
    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);
    }
}

可見,mWindowSession 內(nèi)部最終是將 Window 提交給了 WindowManagerService 去處理耗绿。WindowManagerService 內(nèi)部會(huì)為每一個(gè)應(yīng)用保留一個(gè)單獨(dú)的 Session苹支。

如果再仔細(xì)看,mWindowSession 提交的是一個(gè) IWindow 對(duì)象误阻,也就是 ViewRootImpl 內(nèi)部的 mWindow對(duì)象债蜜,類型是 ViewRootImpl.W。

所以說究反,什么是 Window寻定?如果 Window 是指用來做顯示的一個(gè)抽象概念。那么奴紧,當(dāng)一個(gè)新的 Window 被添加以后特姐,WindowManagerService 中會(huì)增加一個(gè) IWindow 對(duì)象。

值得一提的是黍氮,Activity 的 Window 的創(chuàng)建唐含,也基本遵循這個(gè)過程浅浮,只不過這個(gè)過程是自動(dòng)完成的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捷枯,一起剝皮案震驚了整個(gè)濱河市滚秩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淮捆,老刑警劉巖郁油,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異攀痊,居然都是意外死亡桐腌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門苟径,熙熙樓的掌柜王于貴愁眉苦臉地迎上來案站,“玉大人,你說我怎么就攤上這事棘街◇⊙危” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵遭殉,是天一觀的道長(zhǎng)石挂。 經(jīng)常有香客問我,道長(zhǎng)险污,這世上最難降的妖魔是什么痹愚? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮罗心,結(jié)果婚禮上里伯,老公的妹妹穿的比我還像新娘。我一直安慰自己渤闷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布脖镀。 她就那樣靜靜地躺著飒箭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜒灰。 梳的紋絲不亂的頭發(fā)上弦蹂,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音强窖,去河邊找鬼凸椿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翅溺,可吹牛的內(nèi)容都是我干的脑漫。 我是一名探鬼主播髓抑,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼优幸!你這毒婦竟也來了吨拍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤网杆,失蹤者是張志新(化名)和其女友劉穎羹饰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碳却,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡队秩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昼浦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馍资。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖座柱,靈堂內(nèi)的尸體忽然破棺而出迷帜,到底是詐尸還是另有隱情,我是刑警寧澤色洞,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布戏锹,位于F島的核電站,受9級(jí)特大地震影響火诸,放射性物質(zhì)發(fā)生泄漏锦针。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一置蜀、第九天 我趴在偏房一處隱蔽的房頂上張望奈搜。 院中可真熱鬧,春花似錦盯荤、人聲如沸馋吗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宏粤。三九已至,卻和暖如春灼卢,著一層夾襖步出監(jiān)牢的瞬間绍哎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工鞋真, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留崇堰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像海诲,于是被迫代替她去往敵國(guó)和親繁莹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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