从源码分析 Window 的内部机制

1. Window 的添加过程

1.1 从源头开始

添加一个小悬浮窗是需要通过 WindowManager 的 addView 实现的,

而我们查阅官方文档发现 WindowManager 是一个接口

public interface WindowManager implements ViewManager

它的真正实现是 WindowManagerImpl ,其中有如下代码

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

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

1.2 探寻 WindowManagerGlobal

可以看到,其中把实现 Window 的操作全部交给了 WindowManagerGlobal ,

其以工厂的形式对外提供自己的实例,其中的 addView 主要进行了如下几个工作:

1.2.1 检查参数合法性,以及调整参数
    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);
    } 
1.2.2 创建 ViewRootImpl 并将 View 添加到列表中

先关注 WindowManagerGlobal 中的几个参数

    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

其中 mView 存储所有 Window 对应的 View,mRoot 存储所有 Window 对应的 ViewRootImpl;mParams 存储所有 Window 对应的布局参数;mDyingViews 存储正在被删除的 View 对象,或者说已经调用 removeView 但是删除操作还没有完成的 Window。

在 addView 中通过如下方法将 Window 一系列对象添加到列表中:

    root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
1.2.3 通过 ViewRootImpl 来更新界面并完成 Window 的添加过程

首先,通过 ViewRootImpl 的 setView 方法:

setView 里,通过 requestLayout 完成异步刷新:

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

其中 scheduleTraversals 实际上是 View 绘制的入口。

接着,

        final IWindowSession mWindowSession;        
        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);
        }

这里 mWindowSession 类型是 IWindowSession ,这是一个 Binder 对象,真正实现类是 Session。

也就是说 Window 的添加过程是一次 IPC 调用。

Session 内部会通过 WindowManagerService 实现 Window 的添加。

未完待续,明天再写(逃

猜你喜欢

转载自blog.csdn.net/bestcxcxj/article/details/81460574