An overview of

We all know that the Activity is used to display interface, are set the View to the Window, in the end by WindowManagerService calling the underlying skia rendering engine or OpenGL | ES come true. Let’s summarize the steps first

  1. Activity can not store any view, is handed over to the Window, Android PhoneWindow is the only implementation of the Window class

  2. When you start the Activity, you go to the ActivityThread’s performLaunchActivity method, which executes attach. In attach, you create a PhoneWindow and get the mWindowManager, Namely WindowManagerImpl

  3. Then we go to the Activity’s onCreate method, and we create a DecorView by setContentView(), which is actually calling PhoneWindow setContentView(), and at this point we create a DecorView. It just creates the View, Window, and Activity

  4. After executing the ActivityThread’s handleResumeActivity method, which executes the Activity’s onResume method, It calls WindowManger addView(DecorView View), and actually WindowManger goes to WindowManagerImpl, and then goes to WindowManagerGlobal addView, Then go to root.setView of ViewRootImpl

  5. Then it goes to the SystemServer process session.addTodisplay, and then to the WindowMangerService addWindow().

  6. By the way, ViewRootImpl is not a View. It implements ViewParent, requestLayout, Invalidate, and so on. Any View or screen refresh will be given to ViewRootImpl.

  7. The View inside the setContentView is given to the DecorView to add, and the DecorView is given to the Window

There are roughly three types of Windows

  • System Window: such as Status Bar, Navigation Bar, caller id Window, lock screen Window, volume adjustment Window.
  • Apply Windows: This includes all Windows created by the application itself (such as Windows on Acitivty), as well as Windows that the system is responsible for displaying before application
  • A child Window must have a parent form that applies custom dialogs, such as PopWindow or Dialog

SetContentView (android10, android10, android10, android10

When an Activity is started, it goes to the performLaunchActivity method of the ActivityThread. See my previous article on opening the Activity process

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   ContextImpl appContext = createBaseContextForActivity(r);
   Activity activity = null;
      try {
          java.lang.ClassLoader cl = appContext.getClassLoader();
          // Create a new Activity object with Instrumentation
          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) {

      }
   try {
   // Instead of creating our Application, we get our Application from here.
   // The real place to create it is the mInitialApplication inside the handleBindApplication
       Application app = r.packageInfo.makeApplication(false, mInstrumentation);
   	   if(activity ! =null) {
                CharSequence title = 								       r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if(r.overrideConfig ! =null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if(r.mPendingRemoveWindow ! =null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
             // Go to the attach method of the Activity
                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); }}Copy the code

Let’s look at the Attach method and setContentView for our Activity

 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) {
        attachBaseContext(context);
        // Initialize Window. PhoneWindow is the only implementation class of Window
         mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        //....
        // Get WindowManager from PhoneWindow, and mWindowManager is really WindowManager IMPl
        // WindowMangerImpl
        mWindowManager = mWindow.getWindowManager();
        
public void setContentView(@LayoutRes int layoutResID) {
		// Calls PhoneWindow setContentView
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
}
Copy the code

So let’s look at the setContentView for PhoneWindow

@Override
public void setContentView(int layoutResID) {
        // before this happens.
        if (mContentParent == null) {
        // We initialize a DecorView. The DecorView is a View that inherits FrameLayout
            installDecor();
        } else if(! hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); }Copy the code

Then let’s look at the handleResumeActivity for ActivityThread

@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
        // Execute the Activity's onResume method
    	final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        final Activity a = r.activity;
        // Will go into this
		 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(); }}// mVisibleFromClient defaults to true
            if (a.mVisibleFromClient) {
            // At this point mWindowAdded is false and has not been added yet, so it will go here
                if(! a.mWindowAdded) {// Set mWindowAdded to true
                    a.mWindowAdded = true;
                    // Call the WindowManager addView() method
                    / / WindowManagerGlobal addView ()
              
                    wm.addView(decor, l);
                } else{ a.onWindowAttributesChanged(l); }}}else if(! willBeVisible) {if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        }
        
         if(! r.activity.mFinished && willBeVisible && r.activity.mDecor ! =null && !r.hideForNow) {
           // omit the code
            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            if (r.activity.mVisibleFromClient) {
               // Activity makeVisible at this time just let mDecor. SetVisibility (view.visible);
               // Because window has already been added.r.activity.makeVisible(); }}Copy the code

As you can see, after the Activity’s onResume, it goes to Windows ManagerGlobal and adds the DecorView to the window. Then let’s look at the Windows ManagerGlobal addView method.

  public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
     // omit the code
		
      ViewRootImpl root;
      View panelParentView = null;

        // omit the code
		// Initialize ViewRootImpl
        // ViewRootImpl is not a View, but it implements the ViewParent interface
        // Call the ViewRootImpl method to refresh
          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 {
          // Place the DecorView inside the ViewRootImpl
              root.setView(view, wparams, panelParentView);
          } catch (RuntimeException e) {
              throwe; }}}Copy the code

And then let’s take a look at the setView of view RotimPL

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  synchronized (this) {
    / / to omit
    // This is the binder mechanism, WindowMangerServiceres = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); }}@UnsupportedAppUsage
public static IWindowSession getWindowSession(a) {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {
                InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                IWindowManager windowManager = getWindowManagerService();
                The openSession method of WindowMangerService is actually called.
                sWindowSession = windowManager.openSession(
                        new IWindowSessionCallback.Stub() {
                            @Override
                            public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); }}); }catch (RemoteException e) {
                throwe.rethrowFromSystemServer(); }}returnsWindowSession; }}Copy the code

And then if we look at the Session returned by openSession of WindowMangerService, the Session calls addToDisplay, and eventually calls addWindow of WindowMangerService, All that is left to be said is the WMS and the underlying drawing calls.

reference

Take a Window view of startActivity