美文网首页
ViewRootImpl

ViewRootImpl

作者: Allenlll | 来源:发表于2020-04-22 18:40 被阅读0次

    一、介绍

    1. view层级的顶层,实现了View和WindowManager之间的协议,大部分上WindowManagerGlobal类的具体执行类。
    2. PhoneWindow持有DecorView
      二、一些细节
    3. 线程检查
      有mThread变量获取的是创建ViewRootImpl时的线程,用来检查是否在创建线程进行view的操作。比如requestLayout方法有检查线程,如果线程不同则抛异常。
      final Thread mThread;
       @Override
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                checkThread();
                mLayoutRequested = true;
                scheduleTraversals();
            }
        }
    
     void checkThread() {
            if (mThread != Thread.currentThread()) {
                throw new CalledFromWrongThreadException(
                        "Only the original thread that created a view hierarchy can touch its views.");
            }
        }
    
    1. performTraversals
      performTraversals依次执行了performMeasure,performlayout,performDraw三个方法
    2. ViewRootImpl的初始化
      在ActivityThread中的handlerResumeActivity执行的是Activity的onResume,这里把decorView添加到windowManager中,而WindowManager具体实现类是WindowManagerImpl
      @Override
        public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                String reason) {
            // TODO Push resumeArgs into the activity for consideration
            final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
            final Activity a = r.activity;
    
            if (r.window == null && !a.mFinished && willBeVisible) {
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
    
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        wm.addView(decor, l);//decorView添加到windowManagerk 
                    } else {
                        a.onWindowAttributesChanged(l);
                    }
                }
    
            } 
    
    
        }
    
    
    

    WindowManagerImpl的addView方法,WindowManagerGlobal是一个单例类,实际是通过WindowManagerGlobal添加的View

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

    WindowManagerGlobal,创建ViewRootImpl,把decorView设置到ViewRootImpl绑定Window所对应的View,并对该View进行测试,布局和绘制。

     public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    
            ViewRootImpl root;
            View panelParentView = null;
    
            synchronized (mLock) {
              
                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 {
                    root.setView(view, wparams, panelParentView);
                } catch (RuntimeException e) {
                    // BadTokenException or InvalidDisplayException, clean up.
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
                    throw e;
                }
            }
        }
    
    

    ViewRootImpl的setView

     /**
         * We have one child
         */
        public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
                if (mView == null) {
                    mView = view;
                    //完成view的刷新,以及view的绘制
                    requestLayout();
                  
                    try {
                        //window添加到display
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                                mTempInsets);
                    } catch (RemoteException e) {
                       
                    } finally {
                   
                    }
                    view.assignParent(this);//设置parent
                }
            }
        }
    
    
    • ViewRootImpl对View的操作
    public final class ViewRootImpl implements ViewParent,
            View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    
    
        @Override
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                checkThread();
                mLayoutRequested = true;
                scheduleTraversals();
            }
        }
    
      void checkThread() {
            if (mThread != Thread.currentThread()) {
                throw new CalledFromWrongThreadException(
                        "Only the original thread that created a view hierarchy can touch its views.");
            }
        }
    
      @UnsupportedAppUsage
        void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                if (!mUnbufferedInputDispatch) {
                    scheduleConsumeBatchedInput();
                }
                notifyRendererOfFramePending();
                pokeDrawLockIfNeeded();
            }
        }
    
      final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                doTraversal();
            }
        }
        final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
    
     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, desiredWindowWidth, desiredWindowHeight);
       performDraw();
    }
    
    }
    
    • View的测量
      performMeasure执行window对应的view的测量
    1. ViewRootImpl的performMeasure
    2. DecorView的measure
    3. DecorView的onMeasure
    4. DecorView所有子View的measure
        private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
            if (mView == null) {
                return;
            }
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
            try {
                mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }
    
    • View的布局
      performLayout执行Window对应View的布局
    1. ViewRootImpl的performLayout
    2. DecorView的layout
    3. DecorView的onLayout
    4. DecorView的layoutChildren
    5. DecorView所有子View的layout
      子View的requestLayout方法的执行,会触发 ViewRootImpl方法requstLayout方法的执行,进行重新测试和布局
      private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
                int desiredWindowHeight) {
     
    
            final View host = mView;
            if (host == null) {
                return;
            }
      
            try {
                host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
    
    
                int numViewsRequestingLayout = mLayoutRequesters.size();
                if (numViewsRequestingLayout > 0) {
                    // requestLayout() was called during layout.
                    // If no layout-request flags are set on the requesting views, there is no problem.
                    // If some requests are still pending, then we need to clear those flags and do
                    // a full request/measure/layout pass to handle this situation.
                    ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
                            false);
                    if (validLayoutRequesters != null) {
                        // Set this flag to indicate that any further requests are happening during
                        // the second pass, which may result in posting those requests to the next
                        // frame instead
                        mHandlingLayoutInLayoutRequest = true;
    
                        // Process fresh layout requests, then measure and layout
                        int numValidRequests = validLayoutRequesters.size();
                        for (int i = 0; i < numValidRequests; ++i) {
                            final View view = validLayoutRequesters.get(i);
                            Log.w("View", "requestLayout() improperly called by " + view +
                                    " during layout: running second layout pass");
                            view.requestLayout();//View触发自己的requestLayout会触发ViewRootImpl的requestLayout方法,重新进行布局,绘制。
                        }
                        measureHierarchy(host, lp, mView.getContext().getResources(),
                                desiredWindowWidth, desiredWindowHeight);
                        mInLayout = true;
                        host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
    
                        mHandlingLayoutInLayoutRequest = false;
    
                        // Check the valid requests again, this time without checking/clearing the
                        // layout flags, since requests happening during the second pass get noop'd
                        validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
                        if (validLayoutRequesters != null) {
                            final ArrayList<View> finalRequesters = validLayoutRequesters;
                            // Post second-pass requests to the next frame
                            getRunQueue().post(new Runnable() {
                                @Override
                                public void run() {
                                    int numValidRequests = finalRequesters.size();
                                    for (int i = 0; i < numValidRequests; ++i) {
                                        final View view = finalRequesters.get(i);
                                        Log.w("View", "requestLayout() improperly called by " + view +
                                                " during second layout pass: posting in next frame");
                                        view.requestLayout();
                                    }
                                }
                            });
                        }
                    }
    
                }
            } 
        }
    
    
    • View的绘制过程
    1. ViewRootImpl的performDraw
    2. ViewRoorImpl的draw
    3. ViewRootImpl的drawSoftware
    4. DecorView的draw
    5. DecorView的dispatchDraw
    6. DecorView的drawChild
    7. DecorView所有子View的draw
      private void performDraw() {
    
            try {
                boolean canUseAsync = draw(fullRedrawNeeded);
              
            } finally {
                mIsDrawing = false;
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
    
    
    
      private boolean draw(boolean fullRedrawNeeded) {
           
    
            mAttachInfo.mTreeObserver.dispatchOnDraw();
    
            if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
                if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {      
                  if (updated) {
                        requestDrawWindow();
                    }
                    mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
                } else {
                        scheduleTraversals();
                        return false;
                    if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
                            scalingRequired, dirty, surfaceInsets)) {
                        return false;
                    }
                }
            }
    
            if (animating) {
                mFullRedrawNeeded = true;
                scheduleTraversals();
            }
            return useAsyncReport;
        }
    
    
    
      private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
                boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
    
            // Draw with software renderer.
            final Canvas canvas;
    
           
            try {
     
    
                canvas = mSurface.lockCanvas(dirty);
    
                canvas.setDensity(mDensity);
            } catch (Surface.OutOfResourcesException e) {
                handleOutOfResourcesException(e);
                return false;
            } catch (IllegalArgumentException e) {
              
                return false;
            } finally {
                dirty.offset(dirtyXOffset, dirtyYOffset);  // Reset to the original value.
            }
    
            try {
    
                mView.draw(canvas);
    
                drawAccessibilityFocusedDrawableIfNeeded(canvas);
            } finally {
                try {
                    surface.unlockCanvasAndPost(canvas);
                } catch (IllegalArgumentException e) {
              
                    return false;
                }
          
            }
            return true;
        }
          
    
    
    • 关于异步更新View
      View进行视图更新的时候会触发checkThread,校验当前线程是否是ViewRootImpl被创建时所在的线程。而ViewRootImpl的创建是在Activity的onResume生命周期之后。

    我们可以再onResume之前在异步线程进行视图更新,因为这个时候不会发生线程校验。
    我们可以再异步线程初始化ViewRootImpl同时在该线程进行视图更新。

    • onMeasure
    1. ViewGroup的measureChildren
    2. ViewGroup的measureChild
    3. ViewGroup的measureChildWidthMargins
    4. FrameLayout,LinearLayout,RelativeLayout(View)的onMeasure
    5. View的measure(),计算一个View应该多大,父View提供大小限制,实际的计算大小是这个方法调用的onMeasure方法,必须被子类复写的。
    • onLayout
    1. ViewGroup的onLayout,layout方法调用,为子View布局
    2. ViewGroup(View)的layout,为自己以及子View进行布局
    • draw
    1. draw
    2. onDraw
    3. dispatchDraw
    4. drawchild

    相关文章

      网友评论

          本文标题:ViewRootImpl

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