美文网首页
Android中view的添加源码分析

Android中view的添加源码分析

作者: L_先森0 | 来源:发表于2019-08-12 18:05 被阅读0次

    问题:为什么在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的添加源码分析

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