SoFunction
Updated on 2025-03-01

Android Activity View loading and drawing process in-depth analysis of source code

The startup process from startActivity to Activity is created.

This process is mainly completed by combining between ActivityThread and ActivityManagerService through a binder.

ActivityThread can get AMS's BinderProxy. AMS can get the BinderProxy ApplicationThread of ActivityThread. This way the two sides can communicate with each other.

When ApplicationThread receives the Binder call from AMS, the corresponding operation will be performed through the handler mechanism.

It can be said that handler and binder are two important cornerstones of the Android framework.

The creation of Activity is to call the handleLaunchActivity method in ActivityThread.

 private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
         //Create an Activity and call the lifecycle onCreate method         Activity a = performLaunchActivity(r, customIntent);
          if (a != null) {
             //If the Activity is successfully created, the life cycle onResume method will be called.             handleResumeActivity(, false, ,
                      ! && !);
          }
  }

2. Next, let’s look at performLaunchActivity. Create an Activity.

If the Activity is created successfully, call() first. In this method, a PhoneWindow instance of Activity is created.

Then, the onCreate lifecycle method of the Activity is called.

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
          Activity activity = null;
                try {
                    // Instrumentation mInstrumentation;
                    //Get the class loader and finally create the Activity object through reflection                    //(Activity) (className).newInstance();
                     cl = ();
                    activity = (
                            cl, (), );
                } catch (Exception e) {
                    if (!(activity, e)) {
                        throw new RuntimeException(
                            "Unable to instantiate activity " + component
                            + ": " + (), e);
                    }
                }
                if(activity!=null){
                //Call,                 (appContext, this, getInstrumentation(), ,
                                        , app, , , title, ,
                                        , , config,
                                        );
                }
                //The onCreate method of Activity is called through this method                if (()) {
                    (activity, , );
                    // (icicle, persistentState);
                    // onCreate(icicle, persistentState);
                } else {
                    (activity, );
                    //(icicle);
                    // onCreate(icicle);
                }
          return activity;
}
 final void attach(...){
     //Initialize the subclass of window. Initialize the PhoneWindow. There is a Decoview object in the PhoneWindow.     mWindow = new PhoneWindow(this, window, activityConfigCallback);
     (
                    (WindowManager)(Context.WINDOW_SERVICE),
                    mToken, (),
                    ( & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
     //mWindowManager is an instance of WindowManagerImpl.     mWindowManager = ();
 }

, layout loading process:

In the method, we can display it on the interface through setContentView(.activity_main);, so how does android do it?

1) Call installDecor() to initialize Decorview and mContentParent.

2)(), parse the layout file into the corresponding View in Android.

//GetWindow got PhoneWindow   public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
   }
 @Override
 public void setContentView(int layoutResID) {
    if (mContentParent == null) {
          //Initialize Decorview and mContentParent          installDecor();
      }
    //Load and parse the passed layout file and add to mContentParent.    //This operation is time-consuming because it needs to be parsed from the XML file, and then the View object in Java is generated through reflection.    //So in the recyclerView and listView, cache optimization should be performed.    (layoutResID, mContentParent);
 }

First look at installDecor(), and use generateDecor() to new DecoView instance and assign it to mDecor.

mDecor is a variable of PhoneView.

//mDecorView is a member variable of PhoneWindowprivate DecorView mDecor;
private void installDecor() {
     //Create mDecor     if (mDecor == null) {
         mDecor = generateDecor(-1);
		  //new DecorView(context, featureId, this, getAttributes());
     }
    //Create mContentParent and pass the created DecorView as a parameter     if (mContentParent == null) {
         mContentParent = generateLayout(mDecor);
     }
}

A system layout file is loaded through generateLayout(decor) in the --res-layout directory.

This layout is loaded in the method and added to mDecor.

DecorView inherits from FrameLayout and is a real view.

Then, through findViewbyid, I found a ViewGoup, and I can see the layout file below.

ID_ANDROID_CONTENT = ; , and return this.

This view is mContentParent() in installDecor() method

 protected ViewGroup generateLayout(DecorView decor) {
        int layoutResource;
        //This layout file is in the --res-layout directory.        layoutResource = .screen_simple;
        (mLayoutInflater, layoutResource);
       // int ID_ANDROID_CONTENT = ;
       //This is a FrameLayout defined in screen_simple       //  android:
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        ....
        return contentParent;
  }
   //Load the layout.screen_simple into a view and add it to the DecorView  void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
        ......
         final View root = (layoutResource, null);
        ......
        // Put it below the color views.
         addView(root, 0, new (MATCH_PARENT, MATCH_PARENT));
  }
//.screen_simple
 <LinearLayout xmlns:andro
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:fitsSystemWindows="true"
     android:orientation="vertical">
     <ViewStub android:
               android:inflatedId="@+id/action_mode_bar"
               android:layout="@layout/action_mode_bar"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:theme="?attr/actionBarTheme" />
     <FrameLayout
          android:
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:foregroundInsidePadding="false"
          android:foregroundGravity="fill_horizontal|top"
          android:foreground="?android:attr/windowContentOverlay" />
 </LinearLayout>

Summary: At this point installDecor(); has been completed. Mainly, mDecorView is created and a system layout is loaded, .screen_simple,

Add the loaded View to mDecorView, and assign the view to findViewById() to mParentContent.

Go back to the setContentView and look at the second line of code:

layoutResID is the incoming layout file id, mContentParent is the view with the id "content" in the loaded system layout file

(layoutResID, mContentParent);

  //Load and parse the passed layout file and add to mContentParent.    (layoutResID, mContentParent);
  public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
         return inflate(resource, root, root != null);
   }
   public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
       final Resources res = getContext().getResources();
        //A XML parser is obtained through Resource.       final XmlResourceParser parser = (resource);
       try {
           //Parse our custom layout and add it to mParentContent.           //Parse the ViewGroup and View defined in xml into Java objects.           //This code will be written separately to explain the article           return inflate(parser, root, attachToRoot);
       } finally {
           ();
       }
   }

The above relationship can be summarized as:

Activity-->PhoneWindow-->mDecorView-->addView()-->

-->mParentContent-->addView()

The layout we wrote ourselves has been added to the system's DecorView.

4. We know that there are three important methods for View onMeasure, onLayout, onDraw,

So where are these methods called? How do we add the View we create to the screen?

Going back to the handleLaunchActivity method, there is also a handleResumeActivity. The onResume lifecycle method of the Activity will be executed through performResumeActivity.

   private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
           //Create an Activity and call the lifecycle onCreate method           Activity a = performLaunchActivity(r, customIntent);
            if (a != null) {
               //If the Activity is successfully created, the life cycle onResume method will be called.               handleResumeActivity(, false, ,
                        ! &amp;&amp; !);
            }
   }
  final void handleResumeActivity(IBinder token,
               boolean clearHide, boolean isForward, boolean reallyResume) {
    //Execute the Activity onResume lifecycle method   ActivityClientRecord r = performResumeActivity(token, clearHide);
    if(r!=null){
                final Activity a = ;
                // Through the above code we know that window is PhoneWindow                 = ();
                //Get DecorView                View decor = ();
                //wm is WindowManagerImpl                ViewManager wm = ();
                   if () {
                          = true;
                         //Key code, add decorView to wm                         (decor, l);
                   }
           }
 }
 public final ActivityClientRecord performResumeActivity(IBinder token,
             boolean clearHide) {
        //Execute the Activity onStart onResume method        ActivityClientRecord r = (token);
        ();
     return r;
}
//OnStart onResume lifecycle method in Activity final void performResume(boolean followedByPause, String reason) {
         performRestart(true /* start */, reason);
         (this);
 }
  final void performRestart(boolean start, String reason) {
     if (start) {
         performStart(reason);
      }
  }
public void callActivityOnResume(Activity activity) {
      = true;
     ();
}

After executing the onResume method:

(decor, l);Add Activity's DecorView to wm.

ViewManager wm = ();

ViewManager is an abstract class, and the instance is WindowManagerImpl.

A WindowManagerGlobal object is obtained through singleton mode in WindowManagerImpl.

Since it is an object obtained by singleton mode, there is only one instance in one process, ActivityThread main process.

// addView method//WindowManagerGlobal is a singleton pattern, with only one instance in the ActivityThread main process. private final WindowManagerGlobal mGlobal = ();
    @Override
    public void addView(View view,  params) {
        (view, params, mDisplay, mParentWindow);
 }

private final ArrayList&lt;View&gt; mViews = new ArrayList&lt;View&gt;();
private final ArrayList&lt;ViewRootImpl&gt; mRoots = new ArrayList&lt;ViewRootImpl&gt;();
private final ArrayList&lt;&gt; mParams = new ArrayList&lt;&gt;();
public void addView(View view,  params,
            Display display, Window parentWindow) {
       final  wparams = ()params;
         ViewRootImpl root;
            ........
              root = new ViewRootImpl((), display);
            .........
           (wparams);
         //Save decorView ViewRootImpl into the collection         (view);
         (root);
         (wparams);
         (view, wparams, panelParentView);
}

A ViewRootImpl object is created in WindowManagerGlobal. This is a very important object.

Set the passed DecorView in root (view, wparams, panelParentView);

  public ViewRootImpl(Context context, Display display) {
        mWindowSession = ();
        mThread = ();
  }
 public void setView(View view,  attrs, View panelParentView) {
      // Schedule the first layout -before- adding to the windowmanager,
        //to make sure we do the relayout before receiving
        // any other events from the system.
       //Layout before adding to windowmanager, make sure to relayout before receiving the system event       // The drawing process of the release layout, the drawing process of measure, layout, and view, comes from here.       //This method ensures that measurement and drawing have been completed before the added screen.        requestLayout();
        try {
            //Communicate through binder and WindowManagerService and add the view to the screen.            // mWindow = new W(this);
            // static class W extends  {}
            //Add to the screen logic, write an article for detailed analysis later.             res = (mWindow, mSeq, mWindowAttributes,
                                        getHostVisibility(), (),
                                        , mInputChannel);
        }catch (RemoteException e) {
            throw new RuntimeException("Adding window failed", e);
        }
 }

There are two very important codes in the setView() method.

requestLayout();

res = ()

1) RequestLayout() requests layout, and the caller line code will execute the view's measure, layout, and draw methods.

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

CheckThread There is a very important knowledge point. Why can’t the child thread modify the view created by the main thread?

//mThread is the thread in which the initialization of ViewRootImp is located.//When requestLayout, the thread of the current request layout will be obtained.//If the two threads are inconsistent, an exception will be thrown. Only the original created threads can be modified. Views  void checkThread() {
         if (mThread != ()) {
             throw new CalledFromWrongThreadException(
                     "Only the original thread that created a view hierarchy can touch its views.");
         }
     }

In the scheduleTraversals method. The method in mTraversalRunnable is finally executed through the mChoreographer choreographer object. This code is broken down in the message barrier article in detail.

 //Start traversal void scheduleTraversals() {
   if (!mTraversalScheduled) {
     mTraversalScheduled = true;
        //Send a synchronization message, mentioned in the handler mechanism analysis, synchronization barrier.  A detailed analysis will be made on this knowledge point.            mTraversalBarrier = ().postSyncBarrier();
            //mChoreographer Choreographer.            //Through the choreographer, execute the doTraversal method in runnable            (
                 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
   }
 }
final class TraversalRunnable implements Runnable {
           @Override
           public void run() {
               doTraversal();
           }
    }
void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            ().removeSyncBarrier(mTraversalBarrier);
            performTraversals();
        }
  }

The doTraversal() method is executed in the TraversalRunnable. Three important methods are called here

performMeasure(),performLayout(),performDraw()。

This is why the view drawing process calls onMeasure, onLayout first, and then onDraw.

And these writing methods are called only after being executed onResume. So, this is why we want to get the width and height of the View, but we can't get it before onResume.

 private void performTraversals() {
       //mView DecorView
       final View host = mView;
      // Ask host how big it wants to be
       performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        if (didLayout) {
          performLayout(lp, desiredWindowWidth, desiredWindowHeight);
       }
      performDraw();
}
 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
         (childWidthMeasureSpec, childHeightMeasureSpec);
  }
   private void performLayout( lp, int desiredWindowWidth,
              int desiredWindowHeight) {
        final View host = mView;
         (0, 0, (), ());
  }
   private void performDraw() {
       draw(fullRedrawNeeded);
       //
  }

This is the article about the Android Activity View loading and drawing process that deeply analyzes the source code. For more related Android Activity View content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!