View的绘制二:View的绘制流程

245 阅读3分钟

绘制入口:ActivityThread,我们先来看看ActivityThread中的handleMessage()方法。handleMessage()方法是由ActivityThread中一个名为H的继承了Handler的子类中实现的。

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            ......
            handleLaunchActivity(r, null);
            ......
        } break;
        ......
    }
    if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}

在handleMessage方法中调用了handleLaunchActivity(r, null);启动一个activity,我们再来看看handleLaunchActivity()方法:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......

    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);

        ......
    } else {
        // If there was an error, for any reason, tell the activity
        // manager to stop us.
        try {
            ActivityManagerNative.getDefault()
                .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
        } catch (RemoteException ex) {
            // Ignore
        }
    }
}

在handleLaunchActivity方法中首先调用了performLaunchActivity()方法实例化activity对象。然后调用handleResumeActivity()方法。

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume) {
   ......

    // TODO Push resumeArgs into the activity for consideration
    ActivityClientRecord r = performResumeActivity(token, clearHide);

    if (r != null) {
        final Activity a = r.activity;

        ......

        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);  //重点是addView方法
            }

        // If the window has already been added, but during resume
        // we started another activity, then don't yet make the
        // window visible.
        } else if (!willBeVisible) {
            if (localLOGV) Slog.v(
                TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        }

        // Get rid of anything left hanging around.
        cleanUpPendingRemoveWindows(r);

       ......

    } 
}

handleResumeActivity()方法中会调用performResumeActivity()方法,performResumeActivity()方法中会回调activity生命周期的onResume()方法。handleResumeActivity()中调用了 wm.addView(decor, l)方法,wm指的是WindowManagerImpl类。所有我们再来看看 WindowManagerImpl中的addView方法:

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

在此方法中又调用了 mGlobal.addView(view, params, mDisplay, mParentWindow);mGlobal是WindowManagerGlobal。我们再去WindowManagerGlobal查看addView方法:

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    ......

    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        // Start watching for system property changes.
        if (mSystemPropertyUpdater == null) {
            mSystemPropertyUpdater = new Runnable() {
                @Override public void run() {
                    synchronized (mLock) {
                        for (int i = mRoots.size() - 1; i >= 0; --i) {
                            mRoots.get(i).loadSystemProperties();
                        }
                    }
                }
            };
            SystemProperties.addChangeCallback(mSystemPropertyUpdater);
        }

        int index = findViewLocked(view, false);
        if (index >= 0) {
            if (mDyingViews.contains(view)) {
                // Don't wait for MSG_DIE to make it's way through root's queue.
                mRoots.get(index).doDie();
            } else {
                throw new IllegalStateException("View " + view
                        + " has already been added to the window manager.");
            }
            // The previous removeView() had not completed executing. Now it has.
        }

        // If this is a panel window, then find the window it is being
        // attached to for future reference.
        if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
            final int count = mViews.size();
            for (int i = 0; i < count; i++) {
                if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                    panelParentView = mViews.get(i);
                }
            }
        }

        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.
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
        throw e;
    }
}

在此方法中实例化了一个名为root的ViewRootImpl对象。并调用了root.setView(view, wparams, panelParentView);我们再来看ViewRootImpl中的setView方法的实现:

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();
           
            ......
    }
}

我们可以看到在setView中调用了requestLayout()方法;在来看看requestLayout()方法的实现:

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();  // 校验绘制过程是否在主线程执行
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

在requestLayout()方法中又调用了scheduleTraversals()方法:

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

scheduleTraversals方法中调用了mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null),这里调用了mTraversalRunnable的线程。在这个线程中的run方法中调用了doTraversal()方法:

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

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()方法中主要调用了perforTraversals()方法,在这个方法中调用了View的绘制流程的三大步:

private void performTraversals() {
performMeasure();  //测量    performLayout();  //布局
performDraw();  //绘制}


总结:ActivityThread调用handleResumeActivity()方法,在handleResumeActivity()方法中调用WindowManagerImpl的addView()方法,进而调用WindowManagerGlobal中的addView()方法,在此方法中会创建ViewRootImpl对象,然后调用setView()方法将DecorView、布局属性对象关联。关联成功后调用会依次调用ViewRootImpl的requestLayout()-->scheduleTraversals()-->doTraversal()-->performTraversals();最终在performTraversals()方法中执行绘制流程三大步performMeasure()、performLayout()、performDraw()等方法。