美文网首页
Android View绘制流程一

Android View绘制流程一

作者: Leon_hy | 来源:发表于2018-03-20 15:36 被阅读14次

    我们在Activity的onCreate()、onResume()方法里面获取控件的宽高都为0,如下:

    public class MainActivity extends BaseSkinActivity {
        private static final String TAG = "MainActivity";
        private Button mButton;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main1);
            mButton = findViewById(R.id.button_change);
            Log.d(TAG, "onCreate>>>>>>" + "button的高度===" + mButton.getMeasuredHeight() + "----button的宽度" + mButton.getMeasuredWidth());
        }
        @Override
        protected void onResume() {
            super.onResume();
            Log.d(TAG, "onResume>>>>>>" + "button的高度===" + mButton.getMeasuredHeight() + "----button的宽度" + mButton.getMeasuredWidth());
        }
        }
    
      onCreate>>>>>>button的高度===0----button的宽度0
      onResume>>>>>>button的高度===0----button的宽度0
    

    说明Activity在调用onResume方法时还没有测量控件宽高,在Activity的启动流程分析时,我们在ActivityThread的handleResumeActivity方法看到以下代码:

    //   ViewManager wm = a.getWindowManager(); a是Activity,在Activity的getWindowManager(),
     if (r.activity.mVisibleFromClient) {
              a.mWindowAdded = true;
               wm.addView(decor, l);
     }
    

    会不会是这个addView方法里面进行控件的测量呢??我们在Activity找到了wm的赋值地方

     /**
         * Set the window manager for use by this Window to, for example,
         * display panels.  This is <em>not</em> used for displaying the
         * Window itself -- that must be done by the client.
         *
         * @param wm The window manager for adding new windows.
         */
        public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
                boolean hardwareAccelerated) {
            mAppToken = appToken;
            mAppName = appName;
            mHardwareAccelerated = hardwareAccelerated
                    || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
            if (wm == null) {
                wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
            }
            //这里给mWindowManager赋值,转换为WindowManagerImpl对象
            mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
        }
    

    所以最终是在WindowManagerImpl里面调了addView方法。

      //mGlobal 是在常量赋值的  private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
       @Override
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
    

    然后我们再看WindowManagerGlobaladdView方法

     public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
             省略代码···············
                 ViewRootImpl root;
                 View panelParentView = null;
                //ViewRootImpl是在Window的最顶层,DecorView的parent是ViewRootImpl
                root = new ViewRootImpl(view.getContext(), display);
                view.setLayoutParams(wparams);
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
                // do this last because it fires off messages to start doing things
                try {
                    //setView是将Decor加入到root里面,测量应该是在该方法里面
                    root.setView(view, wparams, panelParentView);
                } catch (RuntimeException e) {
                    // BadTokenException or InvalidDisplayException, clean up.
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
                    throw e;
                }
            }
        }
    

    再进入ViewRootImplsetView方法

      /**
         * We have one child
         */
        public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
            省略代码···············
                     // 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();
              省略代码···············
              }
    

    再进入ViewRootImplrequestLayout方法

        @Override
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                checkThread();
                mLayoutRequested = true;
                scheduleTraversals();
            }
        }
    

    再进入ViewRootImplscheduleTraversals方法

    //在这个方法里面有一个postCallback 线程mTraversalRunnable,这个线程就是正式开始进入测量doTraversal方法。
    void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                mChoreographer.postCallback(
                //mTraversalRunnable线程调用doTraversal方法
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                if (!mUnbufferedInputDispatch) {
                    scheduleConsumeBatchedInput();
                }
                notifyRendererOfFramePending();
                pokeDrawLockIfNeeded();
            }
        }
    
     void doTraversal() {
            if (mTraversalScheduled) {
                mTraversalScheduled = false;
                mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    
                if (mProfile) {
                    Debug.startMethodTracing("ViewAncestor");
                }
                //这个方法应该很熟悉了,我们大部分的View绘制流程文章都是从这个地方开始讲的。
                performTraversals();
    
                if (mProfile) {
                    Debug.stopMethodTracing();
                    mProfile = false;
                }
            }
        }
    
    

    看到performTraversals()就是进入onMeasure的入口了。

    相关文章

      网友评论

          本文标题:Android View绘制流程一

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