This article provides an in-depth understanding of how Android View works. It is recommended to read the article for a sample project, which is linked below:

ViewDemo

The source code analyzed in this article is based on Android SDK 29 (Android 10.0, i.e. Android Q).

Due to the word limit of the nuggets article, it is divided into two articles:

Learn more about how Android View works (Part 1)

Learn more about how Android View works

Android window structure

StartActivity (Intent Intent)** startActivity (Intent Intent)**

// Activity.java
@Override
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}
Copy the code

StartActivity (Intent Intent, @nullable Bundle options)**

// Activity.java
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if(options ! =null) {
        // If options are not empty, the startActivityForResult(@requiresperMission Intent Intent, int requestCode) method is called
        startActivityForResult(intent, -1, options);
    } else {
        // If the formal parameter options is empty, RequiresPermission Intent Intent, int requestCode, @nullable Bundle options Here the formal parameter options is empty, so this method is called
        startActivityForResult(intent, -1); }}Copy the code

StartActivityForResult (@requiresperMission Intent Intent, int requestCode)

// Activity.java
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
    startActivityForResult(intent, requestCode, null);
}
Copy the code

**startActivityForResult(@RequiresPermission Intent intent, Int requestCode (@requiresperMission Intent Intent, int requestCode) Nullable Bundle options)** methods.

**startActivityForResult(@requiresperMission Intent Intent, int requestCode, @nullable Bundle options)

// Activity.java
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    // If it is the first startup, the member variable mParent is null, otherwise it is not null
    if (mParent == null) {
        // If it is the first time to start, execute the following logic
        options = transferSpringboardActivityOptions(options);
        // Call the execStartActivity(Context who, IBinder contextThread, IBinder Token, Activity target, Intent Intent, int requestCode, Bundle options)
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if(ar ! =null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            // If a result is requested, we can make the Activity invisible until the result is received. Setting this code during onCreate(Bundle savedInstanceState) or onResume() will hide the Activity during that time. To avoid flickering, do this only when requesting results, because this guarantees that we will get the information when the Activity completes, no matter what happens to it
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
    } else {
        // If it is not the first startup, execute the following logic
        if(options ! =null) {
            // If the formal parameter options is not empty, StartActivityFromChild (@nonnull Activity child, @requiresperMission Intent Intent, int requestCode @nullable Bundle options) method
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            // If the formal parameter option is empty, Call startActivityFromChild(@nonnull Activity child, @requiresperMission Intent Intent, int requestCode)
            mParent.startActivityFromChild(this, intent, requestCode); }}}Copy the code

**startActivityFromChild(@nonnull Activity child, @requiresperMission Intent Intent, int requestCode)

// Activity.java
public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,
        int requestCode) {
    startActivityFromChild(child, intent, requestCode, null);
}
Copy the code

**startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent, Int requestCode (@nonnull Activity child, @requiresperMission Intent Intent) Int requestCode, @nullable Bundle options)** method

TartActivityFromChild (@nonnull Activity child, @requiresperMission Intent Intent, int requestCode) @nullable Bundle options)**

// Activity.java
public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,
        int requestCode, @Nullable Bundle options) {
    options = transferSpringboardActivityOptions(options);
    // Call the execStartActivity(Context who, IBinder contextThread, IBinder Token, Activity target, Intent Intent, int requestCode, Bundle options)
    Instrumentation.ActivityResult ar =
        mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, child,
            intent, requestCode, options);
    if(ar ! =null) {
        mMainThread.sendActivityResult(
            mToken, child.mEmbeddedID, requestCode,
            ar.getResultCode(), ar.getResultData());
    }
    cancelInputsAndStartExitTransition(options);
}
Copy the code

And we can see, In fact, the final call to the Instrumentation execStartActivity(Context who, IBinder contextThread, IBinder Token, Activity Target, Intent Intent, int requestCode, Bundle options)

// frameworks/base/core/java/android/app/Instrumentation.java
@UnsupportedAppUsage
public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    // Omit some code
    try {
        intent.migrateExtraStreamToClipData(who);
        intent.prepareToLeaveProcess(who);
        / / call ActivityTaskManagerService startActivity method
        intresult = ActivityTaskManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null,
                        requestCode, 0.null, options);
         checkStartActivityResult(result, intent);
     } catch (RemoteException e) {
         throw new RuntimeException("Failure from system", e);
     }
     return null;
}
Copy the code

ActivityTaskManager. GetService () method gets a IActivityTaskManager of interface, it is through the interprocess Communication (Intel – Process Communication, namely the IPC) call, Is ActivityTaskManagerService IActivityTaskManager service end, so it is called ActivityTaskManagerService startActivity method, at the back of the calling process, I’m not going to go into detail here, Is the last call * * handleLaunchActivity ActivityThread class (ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent)**

// frameworks/base/core/java/android/app/ActivityThread.java
@Override
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {
    // Omit some code

    // Call performLaunchActivity(ActivityClientRecord r, Intent customIntent)
    final Activity a = performLaunchActivity(r, customIntent);

    // Omit some code

    / / return the Activity
    return a;
}
Copy the code

**performLaunchActivity(ActivityClientRecord r, Intent customIntent)

// frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // Omit some code

    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        // Reflection creates Activity
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if(r.state ! =null) { r.state.setClassLoader(cl); }}catch (Exception e) {
        if(! mInstrumentation.onException(activity, e)) {throw new RuntimeException(
                    "Unable to instantiate activity " + component
                            + ":"+ e.toString(), e); }}try {
        // Create an Application object, which is a singleton. Each process has only one Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        // Omit some code

        if(activity ! =null) {
            // Omit some code
            // Call the Attach method of the Activity, which creates PhoneWindow, a subclass of the Window abstract class
            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);

            // Omit some code
            // Call the Activity's onCreate method
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            if(! activity.mCalled) {throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                                " did not call through to super.onCreate()");
            }
            r.activity = activity;
        }
        // Set the state to ON_CREATE
        r.setState(ON_CREATE);

        The role of / / updatePendingActivityConfiguration () method from the mActivities reads data to update the ActivityClientRecord, it running in different threads, So take ResourcesManager as the lock object
        synchronized(mResourcesManager) { mActivities.put(r.token, r); }}catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        if(! mInstrumentation.onException(activity, e)) {throw new RuntimeException(
                    "Unable to start activity " + component
                            + ":"+ e.toString(), e); }}/ / return the Activity
    return activity;
}
Copy the code

In this method, the attach method of the Activity is called, with the source code shown below:

// frameworks/base/core/java/android/app/Activity.java
@UnsupportedAppUsage
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, IBinder assistToken) {
    // Omit some code

    // Create the PhoneWindow object and assign it to the member variable mWindow
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    // Omit some code
}
Copy the code

As you can see, the member variable mWindow is actually the PhoneWindow object.

And then we go back to the logic, Then it invokes ActivityThread class handleStartActivity (ActivityClientRecord r, PendingTransactionActions pendingActions) method, The onStart method of the Activity class is then called, Then call the ActivityThread class’s **handleResumeActivity(IBinder Token, Boolean finalStateRequest, Boolean isForward, String reason)**;

// frameworks/base/core/java/android/app/ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                 String reason) {
    // Omit some code

    // Call the Activity's onResume method
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    // Omit some code

    final Activity a = r.activity;

    // Omit some code
    if (r.window == null && !a.mFinished && willBeVisible) {
        The PhoneWindow class inherits the Window class, which is the only subclass of the Window class
        r.window = r.activity.getWindow();
        / / get DecorView
        View decor = r.window.getDecorView();
        // Make the DecorView invisible
        decor.setVisibility(View.INVISIBLE);
        ViewManager is an interface, WindowManger is an interface, it inherits ViewManager interface, where WindowManagerImpl class implements ViewManager interface, The VM here can be thought of as a Windows Mangerimpl object
        ViewManager wm = a.getWindowManager();
        // Omit some code
        if (a.mVisibleFromClient) {
            if(! a.mWindowAdded) { a.mWindowAdded =true;
                // Call the WindowManagerImpl class addView(View View, viewGroup.layoutParams params) method to perform the drawing process
                wm.addView(decor, l);
            } else {
                // Omit some code}}}else if(! willBeVisible) {// If the Window has been added but another Activity is started during the resume, do not make the Window visible
        if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
        r.hideForNow = true;
    }

    // Omit some code
}
Copy the code

The View drawing process is executed after the Activity’s onResume method.

Call WindowManagerImpl addView(View View, viewGroup.layoutParams params) and pass in the DecorView and PhoneWindow properties.

// frameworks/base/core/java/android/view/WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
    @UnsupportedAppUsage
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    // Omit some code

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        // Call the WindowManagerGlobal addView(View View, ViewGroup.LayoutParams params, Display Display, Window parentWindow) method
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

    // Omit some code
}
Copy the code

Look at the WindowManagerGlobal **addView(View View, viewGroup.layoutParams params, Display Display, Window parentWindow)** method, The source code is as follows:

// frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
    // Omit some code

    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        // Omit some code

        // Create the ViewRootImpl object
        root = new ViewRootImpl(view.getContext(), display);

        // Set the LayoutParams in the DecorView
        view.setLayoutParams(wparams);

        // Add the DecorView to the View's ArrayList
        mViews.add(view);
        // Add ViewRootImpl to ViewRootImpl's ArrayList
        mRoots.add(root);
        / / add the LayoutParams DecorView to the WindowManager LayoutParams ArrayList
        mParams.add(wparams);

        try {
            / / call ViewRootImpl setView (View View, WindowManager. LayoutParams attrs, View panelParentView) method
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // Throw BadTokenException or InvalidDisplayException
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throwe; }}}Copy the code

See ViewRootImpl class * * setView (View View, WindowManager. LayoutParams attrs, View panelParentView) * * method, the source code is as follows:

// frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            // If the member variable mView is empty, the passed DecorView is assigned to it
            mView = view;

            // Omit some code
            // Call requestLayout()
            requestLayout();
            // Omit some code

            // Call the View assignParent(ViewParent parent) method
            view.assignParent(this);
            // Omit some code}}}Copy the code

**assignParent(ViewParent)**;

// frameworks/base/core/java/android/view/View.java
@UnsupportedAppUsage
void assignParent(ViewParent parent) {
    if (mParent == null) {
        // If the View does not already have parent, assign the ViewRootImpl passed to the member variable mParent
        mParent = parent;
    } else if (parent == null) {
        // If the formal parameter parent is null, the member variable mParent is null
        mParent = null;
    } else {
        // If the View already has parent, setting parent again will throw a RuntimeException
        throw new RuntimeException("view " + this + " being added, but"
                + " it already has a parent"); }}Copy the code

This method is used to associate ViewRootImpl with a DecorView. In this case, the ViewRootImpl is passed in. ViewRootImpl implements the ViewParent interface. The parentView of a DecorView is ViewRootImpl, so any call to a method such as invalidate() in a child element must traverse to find the parentView and end up calling the ViewRootImpl related method.

RequestLayout () method is used to check the current thread is created in ViewRootImpl thread, the View will be informed if it is to perform rendering process, or you’ll throw CalledFromWrongThreadException abnormalities, will be detailed in the rear.

To sum up:

Window is an abstract class, its concrete implementation is PhoneWindow, WindowManager is the external access to the Window, Window implementation is located in WindowManagerService, Windows Manager and Windows ManagerService interact through Inter-process Communication (IPC).

There are three types of Windows:

  • Application Window: For an Activity, creating an application window can only be done inside the Activity, with a level between 1 and 99.
  • Child window: must be attached to any type of parent window, ranking between 1000 and 1999.
  • System window: Does not need to correspond to any Activity, the application cannot create system window, level 2000 to 2999.

Note that larger Windows are overwritten by smaller Windows.

setContentView(@LayoutRes int layoutResID)

The next commonly used method is setContentView(@layoutres int layoutResID). Note that our Activity class inherits the AppCompatActivity class, as shown below:

// AppCompatActivity.java
@Override
public void setContentView(@LayoutRes int layoutResID) {
    // Call the AppCompatDelegate setContentView(int resId) method
    getDelegate().setContentView(layoutResID);
}
Copy the code

Take a look at the **getDelegate()** method, which looks like this:

// AppCompatActivity.java
@NonNull
public AppCompatDelegate getDelegate(a) {
    if (mDelegate == null) {
        If the mDelegate is empty, the compatdelegate abstract class can call the create(@nonnull Activity Activity, @nullable AppCompatCallback callback) method
        mDelegate = AppCompatDelegate.create(this.this);
    }
    return mDelegate;
}
Copy the code

Appcompat originally appeared in com. Android. Support: Appcompat – v7 library, it is to make the android SDK 7 (android 2.1, namely the android Eclair) equipment can use ActionBar, In com. Android. Support: appcompat – v7:21 or more libraries, appcompat can take 7 (android 2.1, the android SDK Android Eclair or above brings Material Color Palette, Widget coloring, Toolbar, etc., and can replace ActionBarActivity with AppCompatActivity. After the release of the Android SDK 28 (Android 9.0, i.e. Android Pie), the AppCompat library was migrated to the AndroidX library, which is the Android Jetpack component.

Look at the **create(@nonnull Activity Activity, @nullable AppCompatCallback callback)** method of the AppCompatDelegate abstract class, as shown below:

// AppCompatDelegate.java
@NonNull
public static AppCompatDelegate create(@NonNull Activity activity,
        @Nullable AppCompatCallback callback) {
    // Create AppCompatDelegateImpl objects
    return new AppCompatDelegateImpl(activity, callback);
}
Copy the code

The AppCompatDelegateImpl class inherits the AppCompatDelegate abstract class, so look at the **setContentView(int resId)** method of the AppCompatDelegateImpl class.

// AppCompatDelegateImpl.java
@Override
public void setContentView(int resId) {
    // Create a DecorView and add it to the Window
    ensureSubDecor();
    // Find the contentView in the DecorView
    ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
    // Remove all views from contentView
    contentParent.removeAllViews();
    // Add the XML layout to be loaded to the contentView based on the passed resId
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    The onContentChanged() method is a hook method that is called when the content view of the screen changes
    mAppCompatWindowCallback.getWrapped().onContentChanged();
}
Copy the code

The ensureSubDecor() method creates a DecorView, adds it to the Window, and creates a panel menu.

// AppCompatDelegateImpl.java
private void ensureSubDecor(a) {
    if(! mSubDecorInstalled) {// If the DecorView is not already created, call the createSubDecor() method to create the DecorView
        mSubDecor = createSubDecor();

        // Get the title character
        CharSequence title = getTitle();
        if(! TextUtils.isEmpty(title)) {// If title is set, the following logic is performed
            if(mDecorContentParent ! =null) {
                mDecorContentParent.setWindowTitle(title);
            } else if(peekSupportActionBar() ! =null) {
                peekSupportActionBar().setWindowTitle(title);
            } else if(mTitleView ! =null) {
                mTitleView.setText(title);
            }
        }

        applyFixedSizeWindow();

        onSubDecorInstalled(mSubDecor);

        // Flag that the DecorView has been created
        mSubDecorInstalled = true;

        // Create the panel menu
        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
        if(! mIsDestroyed && (st ==null || st.menu == null)) {
            // Refresh the interface by adding refresh notification messages to the message queue corresponding to the main thread. The purpose is to prevent the onCreateOptionsMenu(Nenu Menu) method from being called while the Activity is calling onCreate(@Nullable Bundle savedInstanceState)invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR); }}}Copy the code

The createSubDecor() method creates a DecorView and adds it to the Window.

// AppCompatDelegateImpl.java
private ViewGroup createSubDecor(a) {
    TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);

    if(! a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) { a.recycle();// IllegalStateException is thrown if you use AppCompatActivity but don't have a Theme.AppCompat Theme set
        throw new IllegalStateException(
                "You need to use a Theme.AppCompat theme (or descendant) with this activity.");
    }

    // Set the Window properties
    if (a.getBoolean(R.styleable.AppCompatTheme_windowNoTitle, false)) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
    } else if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBar, false)) {
        // actionBar without title is not allowed
        requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR);
    }
    if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBarOverlay, false)) {
        requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY);
    }
    if (a.getBoolean(R.styleable.AppCompatTheme_windowActionModeOverlay, false)) {
        requestWindowFeature(FEATURE_ACTION_MODE_OVERLAY);
    }
    mIsFloating = a.getBoolean(R.styleable.AppCompatTheme_android_windowIsFloating, false);
    a.recycle();

    // Call the ensureWindow() method to check if the DecorView has been added to the Window
    ensureWindow();
    // Create a DecorView by calling the getDecorView() method of the member variable mWindow. Note that the member variable mWindow is declared as Window. Window is an abstract class, and the implementation class is PhoneWindow, as explained below
    mWindow.getDecorView();

    / / get the LayoutInflater
    final LayoutInflater inflater = LayoutInflater.from(mContext);
    ViewGroup subDecor = null;


    // Add to the corresponding layout according to the flag
    if(! mWindowNoTitle) {if (mIsFloating) {
            // If the window needs to float, add a layout with id abc_dialog_TITLE_MATERIAL
            subDecor = (ViewGroup) inflater.inflate(
                    R.layout.abc_dialog_title_material, null);

            // Floating window can not have action bar, reset flag
            mHasActionBar = mOverlayActionBar = false;
        } else if (mHasActionBar) {
            // If the window has an actionBar, perform the following logic
            TypedValue outValue = new TypedValue();
            mContext.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true);

            Context themedContext;
            if(outValue.resourceId ! =0) {
                themedContext = new ContextThemeWrapper(mContext, outValue.resourceId);
            } else {
                themedContext = mContext;
            }

            // Add the id to the abc_screen_toolbar layout using themedContext
            subDecor = (ViewGroup) LayoutInflater.from(themedContext)
                    .inflate(R.layout.abc_screen_toolbar, null);

            mDecorContentParent = (DecorContentParent) subDecor
                    .findViewById(R.id.decor_content_parent);
            mDecorContentParent.setWindowCallback(getWindowCallback());

            // Pass the property to the DecorContentParent
            if (mOverlayActionBar) {
                mDecorContentParent.initFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY);
            }
            if (mFeatureProgress) {
                mDecorContentParent.initFeature(Window.FEATURE_PROGRESS);
            }
            if(mFeatureIndeterminateProgress) { mDecorContentParent.initFeature(Window.FEATURE_INDETERMINATE_PROGRESS); }}}else {
        if (mOverlayActionMode) {
            // If you want to overwrite the Activity, add a layout with id abc_screen_simple_overlay_action_mode
            subDecor = (ViewGroup) inflater.inflate(
                    R.layout.abc_screen_simple_overlay_action_mode, null);
        } else {
            // If you do not want to overwrite the content of the Activity, add a layout whose ID is abc_screen_simple
            subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
        }

        // Omit some code
    }

    if (subDecor == null) {
        // If the DecorView is still empty at this point, IllegalArgumentException is thrown
        throw new IllegalArgumentException(
                "AppCompat does not support the current theme features: { "
                        + "windowActionBar: " + mHasActionBar
                        + ", windowActionBarOverlay: "+ mOverlayActionBar
                        + ", android:windowIsFloating: " + mIsFloating
                        + ", windowActionModeOverlay: " + mOverlayActionMode
                        + ", windowNoTitle: " + mWindowNoTitle
                        + "}");
    }

    if (mDecorContentParent == null) {
        // If the member variable mDecorContentParent is empty, the TextView with ID title in the DecorView is assigned to the member variable mTitleView
        mTitleView = (TextView) subDecor.findViewById(R.id.title);
    }

    // Make decorations suitable for system Windows, such as Window decorations
    ViewUtils.makeOptionalFitsSystemWindows(subDecor);

    final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
            R.id.action_bar_activity_content);

    / / get the contentView
    final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
    if(windowContentView ! =null) {
        while (windowContentView.getChildCount() > 0) {
            // If there are views added to the Window's contentView, migrate them to the contentView
            final View child = windowContentView.getChildAt(0);
            windowContentView.removeViewAt(0);
            contentView.addView(child);
        }

        windowContentView.setId(View.NO_ID);
        // Add android.r.d.c. tent id to contentView, which is useful for fragments
        contentView.setId(android.R.id.content);

        // decorContent has a foreground drawable setting (Windows contentoverlay), which is empty because we are handling it ourselves
        if (windowContentView instanceof FrameLayout) {
            ((FrameLayout) windowContentView).setForeground(null); }}Call the PhoneWindow setContentView(View View) method
    mWindow.setContentView(subDecor);

    contentView.setAttachListener(new ContentFrameLayout.OnAttachListener() {
        @Override
        public void onAttachedFromWindow(a) {}

        @Override
        public void onDetachedFromWindow(a) { dismissPopups(); }});/ / return DecorView
    return subDecor;
}
Copy the code

To summarize, the implementation of ViewRoot is the ViewRootImpl class, and the WindowMananger is responsible for window management, which is the link between Windows Manager and the DecorView. View processes (measure, layout, and draw) are all done using ViewRoot. When the Activity is created, the DecorView is added to the Window and the ViewRootImpl object is created. And by ViewRootImpl setView (View View, WindowManager. LayoutParams attrs, View panelParentView) method and DecorView connection is established, Each Activity contains a Window that corresponds to an application Window. The implementation of this Window is PhoneWindow, which contains a DecorView, DecorView contains TitleView (the ActionBar container) and ContentView (the window content container), where ContentView is a FrameLayout whose ID is Android.r.d.c. Tent, We call the Activity’s setContentView method to add the content to this FrameLayout, which actually calls the PhoneWindow setContentView method.

Click on the link to read the next article: A deeper understanding of how Android View works

My GitHub: TanJiaJunBeyond

Common Android Framework: Common Android framework

My nuggets: Tan Jiajun

My simple book: Tan Jiajun

My CSDN: Tan Jiajun