美文网首页
Graphic Window windowmanager

Graphic Window windowmanager

作者: xiaoluo | 来源:发表于2022-05-25 14:27 被阅读0次
    Window、WindowManager和WMS的关系
    • Window是抽象类,实现类为PhoneWindow,作用是对View进行管理。
    • WindowManager是接口,继承ViewManager,作用是管理Window,它实现类为WindowManagerImpl。对Window(View)进行添加、更新和删除操作使用WM,WM会将具体的工作交WMS来处理。
    • WM和WMS通过Binder来进行跨进程通信。

    View,Window是抽象概念,却是Android中视图的呈现方式。View不能单独存在,需附着在Window抽象上。Activity、Dialog、Toast,PopUpWindow都是视图,都会对应着一个Window。

    Window创建

    PW和WM关联

    Activity 启动过程中会调用 ActivityThread 的 performLaunchActivity 方法,该方法内部调用Activity的attach方法

    Activity::attach

    final void attach(....) {
           ....
            // 1 
            mWindow = new PhoneWindow(this, window, activityConfigCallback);
            mWindow.setWindowControllerCallback(this);
            mWindow.setCallback(this);
            mWindow.setOnWindowDismissedCallback(this);
            mWindow.getLayoutInflater().setPrivateFactory(this);
           ....
            // 2 
            mWindow.setWindowManager(
                    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                    mToken, mComponent.flattenToString(),
                    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
            if (mParent != null) {
                mWindow.setContainer(mParent.getWindow());
            }
            ....
    

    1 创建Window抽象的实例 PhoneWindow。
    2 getSystemService 方法得到的是WindowManagerImpl实例。

    Window::setWindowManager

        public void setWindowManager(....) {
         //返回WindowManagerImpl
           ....
            //   1
            mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
        }
    

    1 这次创建WMI时将创建它的 PW 作为参数传了进来,WMI就持有了 PW的引用,可以对其进行操作。上面提到过view不能单独存在需要添加到Window。

    WMI的addView操作

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

    1 调用了 WindowManagerGlobal 的 addView 方法,其中最后一个参数mParentWindow 就是上面提到的 PhoneWindow,WMI虽是WM 的实现,但却将功能实现委托给了WMG。

    创建View视图

    如何将Activity对应的View添加到Window呢?入口在onCreate的setContentView处。

    Activity ::setContentView

        public void setContentView(@LayoutRes int layoutResID) {
            getWindow().setContentView(layoutResID);
        }
    

    最终辗转调用到PhoneWindow::setConentView()

        public void setContentView(int layoutResID) {
    ....
               // 1  
                installDecor();
    ....
           // 2
            mLayoutInflater.inflate(layoutResID, mContentParent);
            mContentParent.requestApplyInsets();
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
                cb.onContentChanged();
            }
            mContentParentExplicitlySet = true;
        }
    

    1 DecorView的创建由installDecor完成,通过generateDecor创建DecorView,这个时候DecorView还只是一个空白的FrameLayout。

    2 将Activity的视图添加到DecorView的mContentParent中

    上述过程全部完成,Activity的布局文件也已经成功添加到了DecorView的mContentParent中,但是这个时候DecorView还没有被WindowManager正式添加到Window中。

    将View添加到VM

    在ActivityThread的handleResumeActivity方法中,首先会调用Activity的onResume方法,接着会调用Activity的makeVisible(),正是在makeVisible方法中,DecorView真正地完成了添加和显示这两个过程 。

        void makeVisible() {
            if (!mWindowAdded) {
                ViewManager wm = getWindowManager();
               // 1
                wm.addView(mDecor, getWindow().getAttributes());
                mWindowAdded = true;
            }
            mDecor.setVisibility(View.VISIBLE);
        }
    

    到这里,Activity的View视图被添加到了Window中。

    1 调用WMG的addview方法重绘视图

    视图重绘

    public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
          ....
            if (parentWindow != null) {
                //  1
                parentWindow.adjustLayoutParamsForSubWindow(wparams);
            ....
            ViewRootImpl root;
            View panelParentView = null;
             ....
               //  2 
                root = new ViewRootImpl(view.getContext(), display);
                view.setLayoutParams(wparams);
               // 3 
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
               // 4
                root.setView(view, wparams, panelParentView);
             ....
        }
       //在窗口的添加、更新和删除过程中都会涉及这3个列表
        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>();
    

    1 如果当前窗口要作为子窗口,就会根据父窗口对子窗口的WindowManager.LayoutParams 类型的 wparams 对象进行相应调整。
    2 创建了ViewRootImp并赋值给root
    3 将添加的View保存到View列表中
    4 处将窗口和窗口的参数通过setView方法设置到ViewRootImpl中,可见我们添加窗口这一操作是通过ViewRootImpl来进行的。ViewRootImpl身负了很多职责,主要有以下几点:

    • View树的根并管理View树。
    • 触发View的测量、布局和绘制。
    • 输入事件的中转站。
    • 管理Surface。
    • 负责与WMS进行进程间通信。

    Window的更新

    WMI的updateViewLayout方法会调用WMG的updateViewLayout方法

        public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
            view.setLayoutParams(wparams);
               ....
                mParams.add(index, wparams);
                //  1
                root.setLayoutParams(wparams, false);
        }
    

    ViewRootImpl 的 setLayoutParams 方 法 将 更 新 的 参 数 设 置 到 ViewRootImpl 中。ViewRootImpl 的 setLayoutParams 方法在最后会 调用ViewRootImpl的scheduleTraversals方法

        void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                if (!mUnbufferedInputDispatch) {
                    scheduleConsumeBatchedInput();
                }
                notifyRendererOfFramePending();
                pokeDrawLockIfNeeded();
            }
        }
    

    scheduleTraversals 会触发三大流程

    参考资料:android 进阶解密 android开发艺术探索

    相关文章

      网友评论

          本文标题:Graphic Window windowmanager

          本文链接:https://www.haomeiwen.com/subject/jntgsltx.html