八 Window的添加过程

Window 的添加过程是通过 WindowManager 的 addView 来实现的,WindowManager 是一个接口,实现类是WindowManagerImpl,因此直接看该类的addView().

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

上面代码可以看到,WindowManagerImpl 并没有直接实现三大操作,而是通过桥接模式将操作委托给WindowManagerGlobal,接着看WindowManagerGlobal 中的addView 方法:

    /**
     * WindowManager.LayoutParams继承了ViewGroup.LayoutParams
     */
    public void addView(View view, ViewGroup.LayoutParams params,
                        Display display, android.view.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 android.view.WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final android.view.WindowManager.LayoutParams wparams = (android.view.WindowManager.LayoutParams) params;
        /**
         * 如果是子Window,那么还需要调整一些布局参数
         */
        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.
            /**
             * 如果没有父Window,则设置该视图硬件加速
             */
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }

            /**
             * 创建ViewRootImpl(不是DecorView),是native层与java层View系统通信的桥梁。
             * WMS运行在Native层的。
             *   有的版本中ViewRootImpl继承了Handler类,我们熟知的performTraversals()就是系统收到绘制View的消息之后,
             * 通过调用视图树的各个节点的measure、layout和draw方法来绘制整棵视图树
             */
            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 {
                /**
                 * 将View显示在手机上
                 * 与WMS建立连接后就调用ViewRootImpl的setView方法了
                 * 该方法会向WMS发起显示Dialog或者Activity的DecorView请求
                 */
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

root = new ViewRootImpl(view.getContext(), display)方法比较重要,看构造方法的代码:

    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        /**
         * 获取Window Session,也就是与WindowManagerService(Native层)建立连接
         */
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();
        /**
         * 保存当前线程,更新UI的线程只能是创建ViewRootImpl的线程
         *      在应用开发中,如果在子线程中更新UI会抛出异常,并不是因为只能在UI线程才能更新UI,而是因为
         *  ViewRootImpl是在UI线程中创建的
         */
        mThread = Thread.currentThread();
   }

其中WindowManagerGlobal.getWindowSession();是在WindowManagerGlobal中:

    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    /**
                     * 1、获取WindowManagerService  
                     * FrameWork层通过 getWindowManagerService 获取到IWindowManager 对象(Binder)
                     */
                    IWindowManager windowManager = getWindowManagerService();
                    /**
                     * 2、和WindowManagerService建立一个session(IWindowSession)
                     * 相当于Framework和Native层建立一个长期合作的办事处,双方有什么需求通过这个Session来交换信息
                     */
                    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;
        }
    }

FrameWok 与 WMS 建立Session 之后就调用了 ViewRootImpl 的setView 方法:
WindowManagerDlobal中的addView:


            try {
                /**
                 * 将View显示在手机上
                 * 与WMS建立连接后就调用ViewRootImpl的setView方法了
                 * 该方法会向WMS发起显示Dialog或者Activity的DecorView请求
                 */
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }

ViewRootImpl.setView:

   public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            /**
             * 关注1:请求布局(异步刷新请求),对整个Window的视图进行measure、layout、draw
             */
             requestLayout(); 
            /**
             * 向WMS发起显示当前window的请求
             * mWindowSession的类型是IWindowSession,是一个Binder对象,真正的实现类是Session
             * 是一次远程调用方法的过程(IPC过程)
             */
             res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mInputChannel);
   }

未完待续:requestLayout();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值