View
的工作流程,就是View
进行measure
、layout
和draw
的过程,本篇文章我们就来一起看一下View
是如何开始他的工作流程的。
(注:文中源码基于
Android 12
)
在上篇文章《View体系(五)熟悉又陌生的setContentView》中我们讲过Activity
的结构,包括了Activity
、PhoneWindow
及DecorView
。讲了PhoneWindow
的创建和DecorView
的创建,但此时DecorView
还没有加载到PhoneWindow
中,下面我们就从源码看一下DecorView
是如何加载到PhoneWindow
中的。
当我们调用Activity
的startActivity
时,最终会调用到ActivityThread
的handleLaunchActivity
,代码如下:
android.app.ActivityThread
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
......
final Activity a = performLaunchActivity(r, customIntent);//1
......
注释1处调用performLaunchActivity
创建了一个Activity
,进入performLaunchActivity
方法:
android.app.ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
...
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);//1
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken, r.shareableActivityToken);//2
...
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//3
...
return activity;
注释1处会通过mInstrumentation
的newActivity
方法,使用反射的方式,创建Activity
的实例,注释2处调用activity.attach
方法,在之前的文章中讲过,attach
会创建PhoneWindow
实例,并赋值给传入的window
引用,注释3处最终会调用Activity
的OnCreate
回调方法,进而调用setContentView
方法,创建DecorView
。
在Android12
的源码中,handleLaunchActivity
方法中并不会直接调用handleResumeActivity
方法,而是通过ClientTransaction
类来实现调用handleLaunchActivity
之后再调用handleResumeActivity
,具体的放在后面的文章中讲解。
我们继续看handleResumeActivity
方法:
android.app.ActivityThread
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();//1
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();//2
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;
wm.addView(decor, l);//3
...
注释1处得到了DecorView
,注释2处得到了WindowManager
对象,注释3处调用WindowManager
的addView
方法,将DecorView
作为参数传入,WindowManager
的实现类是WindowManagerImpl
,所以实际调用的是WindowManagerImpl
的addView
方法。再看WindowManagerImpl
的addView
方法:
android.view.WindowManagerImpl
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyTokens(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());//1
}
注释1处又调用了WindowManagerGlobal
的addView
方法:
android.view.WindowManagerGlobal
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
...
ViewRootImpl root;
...
root = new ViewRootImpl(view.getContext(), display);//1
...
root.setView(view, wparams, panelParentView, userId);//2
注释1处创建了ViewRootImpl
实例赋值给root
,注释2处将DecorView
作为参数传入ViewRootImpl
,完成了DecorView
和Window
的绑定。
ViewRootImpl
中还有个方法performTraversals
,这个方法使View
进入正真的工作流程:
android.view.ViewRootImpl
private void performTraversals() {
...
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//1
...
performLayout(lp, mWidth, mHeight);//2
...
performDraw();//3
...
注释1处会执行view
的Measure
过程,注释2处会执行view
的Layout
过程,注释3处会执行view
的Draw
过程。
学习更多知识,请关注我的个人博客:droidYu