从源码的角度分析View的绘制流程

这是View的绘制流程详细的源码分析系列文章,包括ActivityThread#handleResumeActivity到ViewRootImpl#performTraversals()
performMeasure()
performLayout()
performDraw()
还有performMeasure()、performLayout()、performDraw()具体源码分析,系列文章目录如下:

从源的角度分析View的绘制流程(本篇)
源码分析UI绘制三部曲之measure
源码分析UI绘制三部曲之layout
源码分析UI绘制三部曲之draw

温馨提示:以下源码分析会截取源码进行说明,部分方法源码较长会只保留关键代码,其他代码用…省略

为了便于大家更好的理解源码调用逻辑,在看源码之前我们先来看下源码调用流程图
在这里插入图片描述

View的绘制入口是ActivityThread#handleResumeActivity

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
            ...
            
            // TODO Push resumeArgs into the activity for consideration
            // 回调Activity的onResume()
            r = performResumeActivity(token, clearHide, reason);
            
            ...
            
            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 (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
        
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // 注释1
                    wm.addView(decor, l);
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }

        
        } else if (!willBeVisible) {
            if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        }
             
}

可以看到其中又调用了performResumeActivity,此方法会回调Activity的onResume(),注释1处调用了wm.addView(decor, l)传入DecorView和窗口的布局参数,此处的wm是一个接口ViewManager,是通过a.getWindowManager()赋值的,通过这个方法可知wm是ViewManager的实现类WindowManager,此处的a是Activity对象,跟进Activity#getWindowManager

public WindowManager getWindowManager() {
        return mWindowManager;
}

直接返回一个WindowManager对象,继续查找该对象在哪里赋值的

 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
            
            ...
            
             mWindowManager = mWindow.getWindowManager();
            
            ...
}

可以看到是在Activity的attach()中赋值,继续跟进Window#getWindowManager发现,她依旧是返回一个mWindowManager,找到mWindowManager赋值处

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

可以看到,调用WindowManagerImpl的createLocalWindowManager来初始化mWindowManager,继续跟进WindowManagerImpl#createLocalWindowManager

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
}

可以看到返回值是WindowManagerImpl,那么值钱分析的在handleResumeActivity()中调用了vm.addView中的vm是WindowManagerImpl的对象,接着找到WindowManagerImpl#addView

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

可以看到调用了mGlobal的addView方法,mGlobal是WindowManagerGlobal对象,继续跟进WindowManagerGlobal#addView

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


            ViewRootImpl root;
            View panelParentView = null;

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

这里创建了一个ViewRootImpl的对象root,并调用ViewRootImpl#setView,将DecorView传入进去,继续跟进ViewRootImpl#setView发现里面调用了requestLayout()

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

可以看到里面调用了一个checkThread()方法,主要用来检查当前的绘制过程是否是在主线程执行

    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

继续看requestLayout代码,接着又调用了scheduleTraversals()

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

可看到代码中调用了mChoreographer的postCallback方法,里面传入了一个mTraversalRunnable,跟进这个mTraversalRunnable

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

最后会调用TraversalRunnable里面的run(),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;
            }
        }
    }

doTraversal里面接着调用了 performTraversals方法,performTraversals源码太长,就不贴出来了,里面调用了绘制的三大步骤:performMeasure、performLayout、performDraw,本篇文档先分析到此,后续会继续分析performMeasure、performLayout、performDraw具体源码

总结下源码调用逻辑
ActivityThread.H.handleMessage(处理Activity生命周期)
-> ActivityThread#handleLaunchActivity()
-> ActivityThread#performLaunchActivity()
-> ActivityThread#handleResumeActivity()
-> ActivityThread#performResumeActivity() (回调Activity的生命周期onResume())
-> WindowManagerImpl#addView(decorView,layoutParams)
-> WindowManagerGlobal#addView:
root = new ViewRootImpl()
root.setView()
-> ViewRootImpl#requestLayout() (会检查当前线程是否是主线程checkThread)
-> ViewRootImpl#scheduleTraversals()
mChoreographer.postCallback(xx,mTraversalRunnable,xx)
-> ViewRootImpl#TraversalRunnable.run()
-> ViewRootImpl#doTraversal()
-> ViewRootImpl#performTraversals()
performMeasure()
performLayout()
performDraw()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值