当前位置: 代码迷 >> Android >> android之View作图到窗口上的过程
  详细解决方案

android之View作图到窗口上的过程

热度:81   发布时间:2016-04-28 01:46:59.0
android之View绘制到窗口上的过程

以前在研究自定义空间的时候,查看过View和ViewGroup绘制的流程的。只是定性的知道会经过onMeasure—onLayout—onDraw这些流程。上一篇Android视图加载到窗口的过程分析中分析了视图加载到窗口的过程。主要就是一系列的addView操作,这篇就从addView方法开始看看View是如何绘制到窗口上的。

ActivityThread#handleResumeActivity方法

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,            boolean reallyResume) {……ActivityClientRecord r = performResumeActivity(token, clearHide);	……if (r.window == null && !a.mFinished && willBeVisible) {                r.window = r.activity.getWindow();                View decor = r.window.getDecorView();//前面分析过,这个是Window对象所维护的装饰窗口,最顶层的窗口                decor.setVisibility(View.INVISIBLE);                ViewManager wm = a.getWindowManager();//获取WindowManager,继承自ViewManager,不可实例化,是个接口                WindowManager.LayoutParams l = r.window.getAttributes();                a.mDecor = decor;                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;                l.softInputMode |= forwardBit;                if (a.mVisibleFromClient) {                    a.mWindowAdded = true;                    wm.addView(decor, l);// 通过WindowManager添加到窗口                }	……}

可以看到最顶层的装饰窗口在activity resume的时候通过windowManager#addView方法添加。

WindowManagerImpl# addView

public void addView(View view, ViewGroup.LayoutParams params) {        mGlobal.addView(view, params, mDisplay, mParentWindow);}    public void addView(View view, ViewGroup.LayoutParams params,            Display display, Window parentWindow) {        ViewRootImpl root;        View panelParentView = null;		......            root = new ViewRootImpl(view.getContext(), display); // 创建一个ViewRoot对象            view.setLayoutParams(wparams);            if (mViews == null) {                index = 1;                mViews = new View[1];                mRoots = new ViewRootImpl[1];                mParams = new WindowManager.LayoutParams[1];            } else {                index = mViews.length + 1;                Object[] old = mViews;                mViews = new View[index];                 System.arraycopy(old, 0, mViews, 0, index-1);                old = mRoots;                mRoots = new ViewRootImpl[index];                System.arraycopy(old, 0, mRoots, 0, index-1);                old = mParams;                mParams = new WindowManager.LayoutParams[index];                System.arraycopy(old, 0, mParams, 0, index-1);            }            index--;            mViews[index] = view;            mRoots[index] = root;// 将view和ViewRootImp关联起来  ViewRootImp是链接View和WindowManagerService的桥梁            mParams[index] = wparams;        }        try {            root.setView(view, wparams, panelParentView);// 调用ViewRoot的setView方法        } 		......    }

setView:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  	requestLayout(); // 请求UI开始绘制重新绘制View树	......        try {           mOrigWindowType = mWindowAttributes.type;           mAttachInfo.mRecomputeGlobalAttributes = true;           collectViewAttributes();	// 通知WindowManagerService添加一个窗口  会调用到addWindow方法           res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,                     getHostVisibility(), mDisplay.getDisplayId(),                     mAttachInfo.mContentInsets, mInputChannel);        }}

两种情况会导致调用到requestLayout,改变视图显示属性,比如setVisibility,是直接或者间接调用该函数。

@Override    public void requestLayout() {        checkThread();// 本次调用是否是在UI线程调用的。        mLayoutRequested = true;        scheduleTraversals();    }    void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().postSyncBarrier();//分发一个异步消息,处理函数中调用performTraversals()对View进行重新遍历。            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);// mTraversalRunnable是一个Runnable对象            scheduleConsumeBatchedInput();        }    }	final TraversalRunnable mTraversalRunnable = new TraversalRunnable();	    final class TraversalRunnable implements Runnable {        @Override        public void run() {            doTraversal();//执行doTraversal()        }}	void doTraversal() {        if (mTraversalScheduled) {            mTraversalScheduled = false;            mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);	……            try {                performTraversals();            } finally {                Trace.traceEnd(Trace.TRACE_TAG_VIEW);            }		……        }}

View树遍历的核心函数  measure—layout--draw

private void performTraversals() {	......    // Ask host how big it wants to be    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);	......performLayout();……performDraw();……     mIsInTraversal = false;}

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");        try {            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);        } finally {            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }    }

mView.measure(childWidthMeasureSpec,childHeightMeasureSpec);就执行到了熟悉onMeasure(childWidthMeasureSpec,childHeightMeasureSpec);里面。

  相关解决方案