DecorView显示过程

当Activity执行完setContentView后,界面元素已被添加到DecorView中。从ActivityThread的handleResumeActivity方法开始,执行DecorView的显示过程。具体流程如下:

《DecorView显示过程》

1. ActivityThread.handleResumeActivity

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
     ...
     ActivityClientRecord r = performResumeActivity(token, clearHide);
     ...       
     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 (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);//②
                }
      }
      ...
}

取出PhoneWindow中的DecorView对象和布局参数,然后调用ViewManager的addView方法将DecorView加入到窗口中。

2. ViewManager.addView

在代码中的①,获取了Activity中的WindowManager对象,类型为ViewManager ,ViewManager的定义如下:

public interface ViewManager{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

ViewManger主要用于在Activity上添加、删除或更新View的布局,Activity的getWindowManager()方法返回的其实是WindowManagerImpl,ViewManager、WindowManager、WindowManagerImpl三者之间的关系为:
《DecorView显示过程》

3. WindowManagerImpl.addView

ViewManger的addView真正在WindowManagerImpl中现,具体如下:

    ...
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ...
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

可知,WinowManagerImpl的addView方法仅仅是调用了WindowManagerGlobal的addView方法。

4. WindowManagerGlobal.addView

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) {
           ...
        }
    }

首先创建ViewRootImpl对象root,然后设置DecorView(即参数view)的布局参数,最后调用root的setView方法添加view,接下来分析setView的实现过程。
每次执行addView都会创建一个与之对应的ViewRootImpl对象,对象存放到mRoots中。一个view既然可以被add到window上,自然也就可以被remove,当一个view被remove时,需要从mRoots中找到与该view对应的ViewRootImpl对象,然后执行具体的remove操作。ViewRootImpl中有一个类型为View的变量mView,在addView时,mView会被赋值为addView的第一个参数view,可通过ViewRootImpl的getView方法返回mView对象。

5. ViewRootImpl.setView

至此,Activity中的的布局文件已经被添加到DecorView中,但界面中的每个View元素大小、布局位置等信息还没有计算出来,在setView中调用了requestLayout方法,来递归计算每个view的位置、大小和绘制。

6. ViewRootImpl.requestLayout

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

在真正执行遍历布局元素之前,需要检查当前线程是否为主线程。只有主线程才允许操作view。

7. ViewRootImpl.scheduleTraversals

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

在scheduleTraversals中,向mChoreographer post了一个mTraversalRunnable,定义如下

 final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    } 
 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

可知,scheduleTraversals主要调用了doTraversal方法

8. ViewRootImpl.doTraversal

 void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
            performTraversals();
            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

在doTraversal中,通过调用performTraversals实现真正的处理界面元素。

9. ViewRootImpl.performTraversals

perfromTraversals过程如下:

《DecorView显示过程》

    原文作者:Android
    原文地址: http://www.caiyeccy.com/android/2017/02/25/DecorView%E6%98%BE%E7%A4%BA%E8%BF%87%E7%A8%8B
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞