美文网首页
View的加载与绘制(二)

View的加载与绘制(二)

作者: TianFB | 来源:发表于2019-05-17 14:21 被阅读0次

View的加载与绘制(一)

在上一篇文章中我们顺延着setContentView()方法查看了一下将自己的布局添加到Window的上面的过程。添加到Window的布局要通过绘制才能显示到界面上,这一章我们就研究一下View的绘制过程。

View的绘制流程

我们先看一下方法调用流程图

现在我们看一下源码
View绘制的入口是ActivityThread中的handleResumeActivity方法

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
      final Activity a = r.activity;
      //activity的onResume调用
      final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
      //获取当前Activity的 window
      r.window = r.activity.getWindow();
      //获取DecorView
      View decor = r.window.getDecorView();
      //获取Activity中没mWindowManager
      ViewManager wm = a.getWindowManager();
      WindowManager.LayoutParams l = r.window.getAttributes();
      wm.addView(decor, l);
}

接下来看看mWindowManager是什么

/** Retrieve the window manager for showing custom windows. */
    public WindowManager getWindowManager() {
        return mWindowManager;
    }
    mWindowManager = mWindow.getWindowManager();

上面又调用了mWindow中的getWindowManager(),我们知道Window的唯一子类是PhoneWindow。我们直接去看该类的方法

public WindowManager getWindowManager() {
       return mWindowManager;
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

上面的wm指向的是WindowManagerImpl类,接下来看该类中的addView方法

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

wm也是通过WindowManagerGlobal的单例对象调用了他的addView方法

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {

        省略代码

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
            //将view viewRoot params添加到对应的集合中
            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.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

上面的方法创建了ViewRoot 并将root、view、param添加到对应的集合中。并调用ViewRoot的addView方法

 /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                省略代码
                requestLayout();
                省略代码  
              }
         }
    }
    
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    //检查View更新时是否是在主线程
    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
    
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

   private void performTraversals() {
        、、、省略代码
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        、、、省略代码
        performLayout(lp, mWidth, mHeight);
        、、、省略代码
        performDraw();
   }

通过上面的一系列的方法最后调用了performMeasure、performLayout、performDraw。上面的三个方法最终调用了当前Activity的DecorView的measure、layout、draw方法。measure方法中会调用onMeasure,layout中会调用onLayout,draw调用了onDraw。

以上就是View绘制的整个过程。目前只记录流程具体细节以后添加。

该文档是自己的学习记录如有错误欢迎指出。

相关文章

网友评论

      本文标题:View的加载与绘制(二)

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