Android中view的添加源码分析

问题:为什么在Activity的onCreate()、onStart()、onResume()方法中直接通过 View.getHeight() 和 View.getMeasuredHeight() 方法都拿不到View的宽高呢?
首先我们来看Activity的onResume是在什么时候被调用的,在ActivityThread.java 中执行handleResumeActivity()方法

/***
 *在ActivityThread.java 中
 */
@Override
 public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        // TODO Push resumeArgs into the activity for consideration
        
        //performResumeActivity执行Activity的onResume()方法
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);  //注释 Ⅰ
        if (r == null) {
            // We didn't actually resume the activity, so skipping any follow-up actions.
            return;
        }

        final Activity a = r.activity;

        final int forwardBit = isForward
                ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

        // If the window hasn't yet been added to the window manager,
        // and this guy didn't finish itself or start another activity,
        // then go ahead and add the window.
        boolean willBeVisible = !a.mStartedActivity;
        if (!willBeVisible) {
            try {
                willBeVisible = ActivityManager.getService().willActivityBeVisible(
                        a.getActivityToken());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                // Normally the ViewRoot sets up callbacks with the Activity
                // in addView->ViewRootImpl#setView. If we are instead reusing
                // the decor view we have to notify the view root that the
                // callbacks may have changed.
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //开始添加 view ,在wm.addView()方法中会真正调用view的测量、布局、绘制
                    wm.addView(decor, l); //注释 Ⅳ
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
        } else if (!willBeVisible) {
            if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        }
        //省略部分代码...
    }
/** 注释 Ⅰ 的实现
* 在ActivityThread.java中
*/
 public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
            String reason) {
        //省略部分代码..
     r.activity.performResume(r.startsNotResumed, reason); //注释 Ⅱ
 }

/** 注释 Ⅱ 的实现
*在 Activity.java 中
*/
final void performResume(boolean followedByPause, String reason) {
        //省略其他代码... 
        // mResumed is set by the instrumentation
        mInstrumentation.callActivityOnResume(this); //注释 Ⅲ
}

/** 注释  Ⅲ  的实现
* Instrumentation.java中
*/
 public void callActivityOnResume(Activity activity) {
        activity.mResumed = true;
     //在这里就真正执行了Activity的onResume()方法的调用
        activity.onResume(); 
     //省略部分代码..
 }

因此在ActivityThread类中的handleResumeActivity()里面调用performResumeActivity()完成了调用Activity类的onResume()方法的调用。紧接在handleResumeActivity()方法执行完performResumeActivity()后,又执行了wm.addView() (注释 Ⅳ),完成View的添加(包括测量、布局、绘制)。
在handleResumeActivity()方法中的wm.addView()添加view,即调用了WindowManager的实现了WindowManagerImpl中的addView()方法,然后在。WindowManagerImpl中的addView()方法里面又调用WindowManagerGlobal的addView()方法去添加view

/**
* WindowManagerImpl.java
*/
public final class WindowManagerImpl implements WindowManager {
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); //注释 Ⅴ
    }
}

/** 注释 Ⅴ 的实现
* WindowManagerGlobal.java
*/
public final class WindowManagerGlobal {
     public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        //省略部分代码....
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
           //省略部分代码....

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

            view.setLayoutParams(wparams);
            //添加view到List集合中
            mViews.add(view); 
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                //root是ViewRootImpl  在里面实现view的添加
                root.setView(view, wparams, panelParentView); //注释 Ⅵ
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }
}

在ViewRootImpl中的setView()方法里面会调用requestLayout()方法请求布局

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        
     /** 注释 Ⅵ 的实现
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        //省略部分代码....
        
        // Schedule the first layout -before- adding to the window
         // manager, to make sure we do the relayout before receiving
         // any other events from the system.
        //请求布局
        requestLayout(); //注释 Ⅶ
        
        //省略部分代码....
    }
            
    /** 注释 Ⅶ 的实现
    * 在requestLayout()中调用scheduleTraversals()
    */
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals(); //注释Ⅷ
        }
    }
     /** 注释 Ⅷ 的实现
     *在scheduleTraversals()方法中有个异步操作mTraversalRunnable
     */
     void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);   //注释 Ⅸ
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    } 
    /** 注释 Ⅸ 的实现
    *ViewRootImpl里的内部类,执行doTraversal()
    */
   final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal(); // 注释 Ⅹ
        }
    }
       /** 注释 Ⅹ 的实现
       *在doTraversal方法中执行 performTraversals();
       */
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
            //在此方法中真正调用了ViewGroup的布局、测量、绘制
            performTraversals();  

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    } 
     /**
     * 在performTraversals()方法中执行View的测量、布局、绘制
     */
     private void performTraversals() {
        //省略部分代码..
          // Ask host how big it wants to be
         //测量、布局、绘制
          performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
          performLayout(lp, mWidth, mHeight);
          performDraw();
     }
}

在ViewRootImpl类中 performMeasure()的实现

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        if (mView == null) {
            return;
        }
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            //开始view的测量,这里的 mView是 DecorView
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

在ViewRootImpl类中 performLayout()的实现

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,int desiredWindowHeight) {
        mLayoutRequested = false;
        mScrollMayChange = true;
        mInLayout = true;

        final View host = mView;
        if (host == null) {
            return;
        }
        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
            Log.v(mTag, "Laying out " + host + " to (" +
                    host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
        }
      Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
        try {
            //开始布局 这里的host是 DecorView
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
        }
     //省略部分代码....
}

在ViewRootImpl类中performDraw()的实现

private void performDraw() {
    //省略其他代码....
    //开始绘制
    boolean canUseAsync = draw(fullRedrawNeeded);
}

之所以在onCreate()、onStart()、onResume()里通过View.getHeight 和 View.getMeasuredHeight()方法拿到的都是0,是因为在onResume()方法执行完后才进行view的添加(包括测量、布局、绘制)。

你可能感兴趣的:(Android中view的添加源码分析)