美文网首页
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