Android View的绘制流程

发布时间:2022-06-27 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Android View的绘制流程脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

Android 30 更新时间:2021-12-18

文章目录

    • View的绘制流程
    • 1) ActivityThread#handleResumeActivity
      • 1.1) ActivityThread#performResumeActivity
        • 1.1.1) Activity#performResume
        • 1.1.1.1) Instrumentation#callActivityOnResume
      • 1.2) ViewManager
        • 1.2.1) Activity#getWindowManager
        • 1.2.1.1) Activity#attach
        • 1.2.1.1.1) Window#getWindowManager
        • 1.2.1.1.1.1) Window#setWindowManager
      • 1.3) ViewManager#addView
        • 1.3.1) WindowManagerImpl#addView
        • 1.3.1.1) WindowManagerGlobal#addView
        • 1.3.1.1.1) ViewRootImpl#setView
        • 1.3.1.1.1.1) ViewRootImpl#requestLayout
        • 1.3.1.1.1.1.1) ViewRootImpl#scheduleTraversals
        • 1.3.1.1.1.1.1.1) ViewRootImpl#doTraversal
        • 1.3.1.1.1.1.1.1.1) ViewRootImpl#performTraversals
        • 1.3.1.1.1.1.1.1.1.1) ViewRootImpl#measureHierarchy
        • 1.3.1.1.1.1.1.1.1.2) ViewRootImpl#performMeasure
        • 1.3.1.1.1.1.1.1.1.2.1) View#measure
        • 1.3.1.1.1.1.1.1.1.3) ViewRootImpl#performLayout
        • 1.3.1.1.1.1.1.1.1.4) ViewRootImpl#performDraw

View的绘制流程

Android View的绘制流程

1) ActivityThread#handleResumeActivity

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
    // Activity对象持有者
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    // 获取到Activity
    final Activity a = r.activity;
    // 获取到PhoneWindow
    r.window = r.activity.getWindow();
    // 获取到DecorView
    View decor = r.window.getDecorView();
    // 设置DecorView不可见
    decor.setVisibility(View.INVISIBLE);
    // 获取到WindowManager
    ViewManager wm = a.getWindowManager();
    // 获取到PhoneWindow的布局属性
    WindowManager.LayoutParams l = r.window.getAttributes();
    // 将 DecorView 添加到 ViewManager
    wm.addView(decor, l);
}

1.1) ActivityThread#performResumeActivity

来看下 performResumeActivity() 方法里面的内容: 里面调用了Activity的performResume方法

public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) {
    final ActivityClientRecord r = mActivities.get(token);
    r.activity.performResume(r.startsNotResumed, reason);
}

1.1.1) Activity#performResume

再看下 r.activity.performResume(r.startsNotResumed, reason); 的内容: 这里又调用了 callActivityOnResume方法

final void performResume(boolean followedByPause, String reason) {
    mInstrumentation.callActivityOnResume(this);
}

1.1.1.1) Instrumentation#callActivityOnResume

再往 mInstrumentation.callActivityOnResume(this); 看: 最后会调用 onResume() 方法

public void callActivityOnResume(Activity activity) {
    activity.onResume();
}

1.2) ViewManager

ViewManager wm = a.getWindowManager(); ViewManager 是一个接口,WindowManager 会继承它

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

1.2.1) Activity#getWindowManager

WindowManager 继承 ViewManager,通过getWindowManager方法,返回了mWindowManager,那 mWindowManager在哪赋值的呢?

public WindowManager getWindowManager() {
    return mWindowManager;
}

1.2.1.1) Activity#attach

mWindowManager 会在 attach中进行赋值,这里调用的是mWindow.getWindowManager() ,再往里面看

final void attach(...) {
    // 创建 PhoneWindow 对象
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    // 获取 WindowManager 
    mWindowManager = mWindow.getWindowManager();
}

1.2.1.1.1) Window#getWindowManager

会返回 mWindowManager,再去看 它是什么时候被赋值的

public WindowManager getWindowManager() {
    return mWindowManager;
}

1.2.1.1.1.1) Window#setWindowManager

mWindowManager 在什么时候被赋值的呢,是在 setWindowManager 方法中,从 WindowManagerImpl拿到的;

另外,WindowManagerImpl 是 WindowManager 的实现类;

ViewManager wm = a.getWindowManager(); 是 从 WindowManagerImpl 拿到的;

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    mAppToken = appToken;
    mAppName = appName;
    mHardwareAccelerated = hardwareAccelerated;
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

1.3) ViewManager#addView

wm 为 ViewManager; WindowManager 继承 ViewManager; WindowManagerImpl 是 WindowManager 的实现类;

那 wm.addView(decor, l); 也就是 调用的 WindowManagerImpl 的 addView方法;

1.3.1) WindowManagerImpl#addView

来看下 WindowManagerImpl 的 addView 方法: 是调用了 WindowManagerGlobal 的 addView 方法

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    // WindowManagerGlobal mGlobal
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
            mContext.getUserId());
}

1.3.1.1) WindowManagerGlobal#addView

WindowManagerGlobal 是管理整个进程,所有的窗口信息的; 看下它的 addView方法内容

public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId) {
    ViewRootImpl root;
    // 创建 ViewRootImpl 对象
    root = new ViewRootImpl(view.getContext(), display);
    
    mViews.add(view);  // DecorView
    mRoots.add(root);  // ViewRoomImpl
    mParams.add(wparams);  // WindowManager.LayoutParams
    
    // DecorView 和 ViewRootImpl 关联
    root.setView(view, wparams, panelParentView, userId); 
}       

1.3.1.1.1) ViewRootImpl#setView

ViewRootImpl 是 操作自己的窗口

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
    mView = view;
    // 请求遍历
    requestLayout();
    // 将窗口添加到 WindowManagerService 上
    res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mDisplayCutout, inputChannel,
                            mTempInsets, mTempControls);
    view.assignParent(this);
}

1.3.1.1.1.1) ViewRootImpl#requestLayout

进行请求遍历操作

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

public ViewRootImpl(Context context, Display display, IWindowSession session, boolean useSfChoreographer) {
    mThread = Thread.currentThread();
}

1.3.1.1.1.1.1) ViewRootImpl#scheduleTraversals

在 scheduleTraversals 中得 postCallback中有一个mTraversalRunnable,可以看到它最终调用 doTraversal 方法;

@UnsupportedAppUsage
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // 看这个 mTraversalRunnable
        mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

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

1.3.1.1.1.1.1.1) ViewRootImpl#doTraversal

performTraversals 是 绘制开始的地方

void doTraversal() {
    performTraversals();
}

1.3.1.1.1.1.1.1.1) ViewRootImpl#performTraversals

在 performTraversals 中,会进行预测量,测量,布局,绘制等操作;

 private void performTraversals() {
    boolean windowSizeMayChange = false;
    // 预测量
    windowSizeMayChange |= measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight);
    // 布局窗口
    relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
    // 测量
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    // 布局
    performLayout(lp, mWidth, mHeight);
    // 绘制
    performDraw();
}

1.3.1.1.1.1.1.1.1.1) ViewRootImpl#measureHierarchy

预测量,会进行三次

private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
    boolean goodMeasure = false;
    if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
        res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
        if (baseSize != 0 && desiredWindowWidth > baseSize) {
            childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
            childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
            
            // 第一次测量
            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
            if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
                goodMeasure = true;
            } else {
            
                // 第二次测量
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
                    if (DEBUG_DIALOG) Log.v(mTag, "Good!");
                    goodMeasure = true;
                }
            }
        }
    }
    if (!goodMeasure) {
        childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
        childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
        
        // 第三次测量
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
            windowSizeMayChange = true;
        }
    }
}

1.3.1.1.1.1.1.1.1.2) ViewRootImpl#performMeasure

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

1.3.1.1.1.1.1.1.1.2.1) View#measure

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    onMeasure(widthMeasureSpec, heightMeasureSpec);
}

// 当自己重写 onMeasure 的时候,需要调用setMeasuredDimension,否则会抛出异常
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

1.3.1.1.1.1.1.1.1.3) ViewRootImpl#performLayout

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) {
    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}

1.3.1.1.1.1.1.1.1.4) ViewRootImpl#performDraw

private void performDraw() {
    boolean canUseAsync = draw(fullRedrawNeeded);
}

Android setContentView流程:https://blog.csdn.net/yan13507001470/article/details/121588583

请多指教。

脚本宝典总结

以上是脚本宝典为你收集整理的Android View的绘制流程全部内容,希望文章能够帮你解决Android View的绘制流程所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: