Andoird WindowManager管理Window的流程

前言

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

一 Window基础

添加、更新、删除一个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);

参数说明:
1、flag,控制Window的显示特性,参数很多可自行查询API,常用如下
FLAG_NOT_TOUCH_MODAL:Window区域内的点击事件自己处理,之外的传递给底层Window,通常打开此标记
FLAG_NOT_FOCUSALE:不需要焦点,直接传递到底层Window
FLAG_SHOW_WHEN_LOCKED:顾名思义,显示在锁屏上
2、type,三种类型。Window是分层的
应用Window:层级1-99,对应一个activity
子Window:层级1000-1999,需要在特定的父Window中,比如Dialog
系统Window:层级2000-2999,需添加权限SYSTEM_ALERT_WINDOW,比如状态栏

二 过程分析

2.1 添加过程

ViewManager只是个interface,搜索源码,实现类为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对应的view、ViewRootImpl和布局参数
ViewRootImpl:WindowManager创建它来管理view
最后通过ViewRootImpl.setView来设置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,其实现是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);
    }

所以其实是WindowManagerService的addWindow,这里addWindow就是WindowManagerService把window如何布置到屏幕上的具体深入细节了,就不跟了。

2.2 删除过程

WindowManagerGlobal的removeView调用

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);延时调用,最终还是会直接调用doDie();

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

doRemoveView,刷新mViews,mRoots,mParams数据
dispatchDetachedFromWindow中主要行为三点:

void dispatchDetachedFromWindow() {
        if (mView != null && mView.mAttachInfo != null) {
            mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
        //调用view的dispatchDetachedFromWindow,资源回收,中止动画线程
            mView.dispatchDetachedFromWindow();
        }

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

        destroyHardwareRenderer();
    //垃圾回收,清空,设为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调用,最后调用到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调用performTraversals,这个就是所有view的绘制过程了,重绘时会调用relayoutWindow然后调用mWindowSession.relayout,即WindowManagerService的relayoutWindow方法

总结

Windowmanager通过ViewRootImpl来添加、更新和删除window,最终的实现都是WindowmanagerService具体实现。本文目的也是掌握Windowmanager管理window的流程。

你可能感兴趣的:(Andoird WindowManager管理Window的流程)