From the activity setContentView() method from the source point of view to parse the Android UI drawing process.

Let’s look at how a View is added to a screen window:

First open the activity’s setContentView() method.

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}Copy the code

The activity’s setContentView() method is the setContentView of the getWindow() method. The getWindow() method returns Window. The Window class is an abstract class that has only one implementation class called PhoneWindow. So we can go to the PhoneWindow class and look at the setContentView method as follows:

@Override
public void setContentView(int layoutResID) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    if (mContentParent == null) {
        installDecor();
    } else if(! hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); }if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if(cb ! = null && ! isDestroyed()) { cb.onContentChanged(); } mContentParentExplicitlySet =true;
}Copy the code

Here we focus on the installDecor() and mLayOutInflater.inflate (layoutResID, mContentParent) methods. Let’s first look at the implementation of the installDecor() method:

private void installDecor() {
    mForceDecorInstall = false;
    if(mDecor == null) { mDecor = generateDecor(-1); / / to mDecor assignment mDecor. SetDescendantFocusability (ViewGroup. FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true);
        if(! mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures ! = 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); }}else {
        mDecor.setWindow(this);
    }
    if(mContentParent == null) { mContentParent = generateLayout(mDecor); . }}Copy the code

Firstly, in the instanllDecor() method, mDecor is judged whether it is empty. MDecor is DecorView. DecorView is a layout inherited from FrameLayout. If mDecor is empty, generateDecor() is called, in which a DecorView object is created.

If the mDecor is null, then the generateLayout(mDecor) method will be called. In this method, the mDecor value is assigned to the mContentParent.

protected ViewGroup generateLayout(DecorView decor) { // Apply data from current theme. TypedArray a = getWindowStyle();  . // Call requestFeature() and based on the theme stylesetFlags() and so on. // Inflate the window decor. int layoutResource; int features = getLocalFeatures(); // System.out.println("Features: 0x"+ Integer.toHexString(features)); // The layoutResource is set to a different value depending on the features set.if((features & (1 << FEATURE_SWIPE_TO_DISMISS)) ! = 0) { layoutResource = R.layout.screen_swipe_dismiss;setCloseOnSwipeEnabled(true); . Save a few hundred lines of code hereelse if((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) ! = 0) { layoutResource = R.layout.screen_simple_overlay_action_mode; }else {
        // Embedded, so no decoration is needed.
        layoutResource = R.layout.screen_simple;
        // System.out.println("Simple!"); } mDecor.startChanging(); // Resolve layoutResource to view and add view to DecorView mDecor. OnResourcesLoaded (mLayoutInflater, layoutResource); Android_content = ID_ANDROID_CONTENT = ID_ANDROID_CONTENT = ID_ANDROID_CONTENT = ID_ANDROID_CONTENT = ID_ANDROID_CONTENT ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);if (contentParent == null) {
        throw new RuntimeException("Window couldn't find content container view"); }...return contentParent;
}Copy the code

This method focuses on mDecor. OnResourcesLoaded (mLayoutInflater, layoutResource); Call the onResourcesLoaded() method in the DecorView.

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) { ...... Final View root = inflater.inflate(layoutResource, null);if(mDecorCaptionView ! = null) {if (mDecorCaptionView.getParent() == null) {
            addView(mDecorCaptionView,
                    new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
        mDecorCaptionView.addView(root,
                new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
    } else{ // Put it below the color views. DecorView (root, 0, new viewGroup.layoutParams (MATCH_PARENT, MATCH_PARENT)); } mContentRoot = (ViewGroup) root; initializeElevation(); }Copy the code

You can see that the onResourcesLoaded() method of the DecorView does two main things: parsing layoutResource as a root object and adding root to the DecorView.

To summarize the installDecor() method in PhoneWindow: A DecorView root layout is created through the generateDecor() method. The generateLayout() method is then called to render different layouts for different themes and add them to the DecorView.

PhoneWindow calls mLayOutInflater.inflate (layoutResID, mContentParent) after calling the installDecor() method in the setContentView; Here layoutResID is the layout ID set in our activity, and mContentParent is the @Android: ID/Content layout defined by ID for the Android system, as shown in the figure below. The final layout we define in the activity is added to the mContentParent.





Summary: How are views added to the screen?

1. The system creates a top-level layout container, DecorView, which inherits from FrameLayout and is an instance of the PhoneWindow object, which is the top-level View of all applications and initialized internally.

2. After the DecorView is initialized, a base container is loaded according to the theme style of the application, such as NoActionBar, DarkActionBar. But each container has a container internally defined by the Android system with the id of Android.r.tent FrameLayout.

3. The layout set by the developer through setContentView is added to the FarmeLayout container.