美文网首页
Android ViewRootImpl学习

Android ViewRootImpl学习

作者: Lonelyyy | 来源:发表于2018-02-14 22:01 被阅读0次

    ViewRootImpl与Activity,Window,WindowManagerService的关系比较紧密,初次接触很难理解它们之间的关系
    简单来说ViewRootImpl负责管理Activity的view,主要处理view的测量,布局,绘制等事务,即measure,layout和traversal

    1.ViewRootImpl的创建与初始化

    Activity创建的时候会走到WindowManagerGlobal的addView方法,这里面会创建一个ViewRootImpl对象

    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);
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
                try {
                    root.setView(view, wparams, panelParentView);
                } catch (RuntimeException e) {
                    // BadTokenException or InvalidDisplayException, clean up.
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
                    throw e;
                }
            }
        }
    

    用于构造ViewRootImpl的参数view是一个DecorView对象,继续看构造函数的实现

    public ViewRootImpl(Context context, Display display) {
            mContext = context;
            mWindowSession = WindowManagerGlobal.getWindowSession();
            mDisplay = display;
            mBasePackageName = context.getBasePackageName();
            mThread = Thread.currentThread();
            mLocation = new WindowLeaked(null);
            mLocation.fillInStackTrace();
            mWidth = -1;
            mHeight = -1;
            mDirty = new Rect();
            mTempRect = new Rect();
            mVisRect = new Rect();
            mWinFrame = new Rect();
            mWindow = new W(this);
            mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
            mViewVisibility = View.GONE;
            mTransparentRegion = new Region();
            mPreviousTransparentRegion = new Region();
            mFirst = true; // true for the first time the view is added
            mAdded = false;
            mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                    context);
            mAccessibilityManager = AccessibilityManager.getInstance(context);
            mAccessibilityManager.addAccessibilityStateChangeListener(
                    mAccessibilityInteractionConnectionManager, mHandler);
            mHighContrastTextManager = new HighContrastTextManager();
            mAccessibilityManager.addHighTextContrastStateChangeListener(
                    mHighContrastTextManager, mHandler);
            mViewConfiguration = ViewConfiguration.get(context);
            mDensity = context.getResources().getDisplayMetrics().densityDpi;
            mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
            mFallbackEventHandler = new PhoneFallbackEventHandler(context);
            mChoreographer = Choreographer.getInstance();
            mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
            if (!sCompatibilityDone) {
                sAlwaysAssignFocus = true;
                sCompatibilityDone = true;
            }
            loadSystemProperties();
        }
    

    里面大部分都和窗口的参数相关,比较重要的成员有这么几个

    • mContext 表面其对应的activity
    • mWindowSession 建立与WMS的联系,唯一性的标识
    • mChreographer 处理视图的刷新
      完成ViewRootImpl的构造之后就会把decorView以及窗口的params给设置过去

    2.requestLayout

    setView方法的内容比较多,里面会执行到requestLayout(),看一下这个函数的具体实现

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

    checkThread用于线程检查,继续看scheduleTraversals方法

    void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                if (!mUnbufferedInputDispatch) {
                    scheduleConsumeBatchedInput();
                }
                notifyRendererOfFramePending();
                pokeDrawLockIfNeeded();
            }
        }
    

    变量mTraversalScheduled的存在是防止重复调用,如果当面没有正在进行布局的操作,则向Choreographer注册了一个回调,我们知道,Choreographer是负责接收vsync信号并且将其发送到各个使用的客户端,所以注册回调之后,等待vsync来了之后就可以进行相应的操作了
    注册的callback类型是CALLBACK_TRAVERSAL,接收到vsync信号之后重新对view进行layout,对于ViewRootImpl来说是执行mTraversalRunnable,看一下这个runnable

    final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                doTraversal();
            }
        }
    
    void doTraversal() {
            if (mTraversalScheduled) {
                mTraversalScheduled = false;
                mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
                if (mProfile) {
                    Debug.startMethodTracing("ViewAncestor");
                }
                performTraversals();
                if (mProfile) {
                    Debug.stopMethodTracing();
                    mProfile = false;
                }
            }
        }
    

    可见,最终是走到了performTraversals()方法,performTraversals是view绘制的关键方法,但是这个方法比较长而且复杂,放到后面再讲

    相关文章

      网友评论

          本文标题:Android ViewRootImpl学习

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