Adventure of activity display interface

Time:2021-5-4

preface

stayActivity display viewThere are some important roles that people can’t understand clearly, such asPhoneWindow、DecorView、ViewRootImpl

Also often have the interview question to be able to ask, between them four relations? When to create it? When is the first time view draws? And so on.

So today, let’s start with youActivityStart to see what steps will be taken in the whole process of view display, and what is the relationship between the roles.

Animation display

In order to facilitate your understanding, I will show you the relationship of these people in the form of animation

Source code analysis

From the birth of love

stayActivityBefore the display of the interface, it was still an activity that we couldn’t see. I gave it a nickname——Little love.

How was little love born? Anyone familiar with the activity startup process knows that the creation of Xiaoai took place inperformLaunchActivityMedium:

//ActivityThread.java
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //Create contextimpl
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //Create an activity
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
        }

        try {
            if (activity != null) {
                //Complete the initialization of some important data of 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);

                //Call the oncreate method of activity
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
            }
        }

        return activity;
    }

In this process, we mainly did three things

  • ActivityBe instantiated
  • CalledattachMethod
  • callonCreateMethod to load the layout from the layout file and prepare for the view display.

Find a helper for Xiao AI to interact with view (phonewindow)

As we all know,Little loveAfter being created, the business is busy, so you can’t manage each one personallyViewSo he found a helper to help her interact with view and manage view.

(decoupling of activity and view)

What is this helper? This is window, which is the implementation classPhoneWindowIt’s too late.

This process takes place inattachIn the method:

//Activity.java
final void attach() {
		//Create phonewindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setCallback(this);
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        
    }

For the convenience of memory, we are in charge of thisPhoneWindowThe housekeeper’s name isWindow manager

Load layout file (decorview)

With the window manager, you can continueonCreateThis is the most important method in oncreatesetContentViewIt’s too late.

adoptsetContentViewYou can load the view in the layout file.

As I said before, the view related management work is handed over to the window manager, so it is directly called to the window managerPhoneWindowOfsetContentViewmethod:

//Activity.java
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

Then you start loading the layout file.

But with one thing in mind,ActivityThere are different themes, and different themes have different layout structures. So before loading the layout file we set ourselves, we need to set oneTop viewAs the leader of all views.

And the top view isDecorViewFor convenience, I call him the youngest brotherLittle brother

Look at meDecorViewHow it was created:

//PhoneWindow.java
    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } 


        if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
    }


    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor(-1);
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);       
        }
    }


    protected DecorView generateDecor(int featureId) {
        return new DecorView(context, featureId, this, getAttributes());
    }

this is it,DecorviewIt’s created, and then it’s time for my little brother to work.

As mentioned above,DecorviewWhat was created for?

To set up different layout structures according to different themes, this work takes place ingenerateLayoutThe method is right. We will not analyze the details today.

It seems that my little brother’s work has been completed?

Wait, the layout of the application has not been loaded yet, and the important things have not been started yet.

And back to the topsetContentViewMethod, calling theinstallDecorMethod after creating a little brother, we also do one thing:

//Loading xml layout file
	mLayoutInflater.inflate(layoutResID, mContentParent);



    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
        
        final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }

And this oneinflateIt’s a familiar way to load layout files. Pass in the XML layout file, parse and combine theParent view -- mcontentparentTo convert it into a complete tree structure, and finally return to the top view.

Come here,setContentViewIt’s done,

In short, it’s creatingDecorviewAnd combine thisTop viewAnd what we brought inXML layout fileTo generate a multi-layer structureView

Display the view (viewrootimpl)

ViewYes, the structure is settled. The next step is how to show thisView structureLet our mobile phone show the picture?

Yes, it isdraw

Who is better to do the drawing work of view? Remember the present members:

  • Little love activityBig boss, take charge of overall planning.
  • Window manager phonewindow: responsible for managing all views.
  • Decorview: the top view, which is responsible for displaying the theme layout.

No one seems to be in chargeViewDid you draw it? Drawing is so important that we need to recruit another friend.

ViewRootImplShining ✨ For convenience, I call himWei

When was Xiaowei founded?

Keep lookingActivityAfter oncreate is called, it will be calledonResumeMethods, this should start fromhandleResumeActivityI’m talking about the method.

@Override
    public void handleResumeActivity() {
        //onResume
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        //addView
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes()
            wm.addView(decor, l);
        }

This method mainly does two things

  • callonResumemethod
  • Calling WM’saddViewmethod.

It seems that Xiao Wei hasn’t come out yet?

Continue to look at the addview method

//WindowManagerGlobal.java
	public void addView() {
        
        synchronized (mLock) {
            
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);


            try {
                root.setView(view, wparams, panelParentView);
            } 
        }
    }



    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mThread = Thread.currentThread();
    }

Finally, WeiViewRootImplIt has also been created. In this viewrootimpl, there are two variables worth paying attention to:

  • mWindowSession. Iwindowsession is a binder object for interprocess communication. The server-side implementation is session, which can be used to complete WMS related work.
  • mThread. Set the thread variable to the current thread, that is, the thread when instantiating viewrootimpl. Generally, when updating UI by different threads, it will judge whether the current thread and mthread are equal. If they are different, an exception will be thrown.

Next, callViewRootImplOfsetViewMethod, this method is the way Xiaowei viewrootimpl does things

//ViewRootImpl.java
    public void setView() {
        synchronized (this) {
        	//Draw
        	requestLayout();

        	//Calling addwindow method of WMS
        	res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);

        	//Set this (viewrootimpl) as the parent of view (decorview)
			view.assignParent(this);
        }
    }

It has three main functions

  • Trigger drawing (including measurement, layout and drawing)
//ViewRootImpl.java
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

    ->scheduleTraversals()
    ->performMeasure() performLayout() performDraw()
    ->Measure, layout and draw methods
  • Calling addwindow method of WMS through binder

Finally, the addtodisplay method allocates a surface to the window using the addwindow method of the WMS process, and theSurfaceIs responsible for the display of the final interface, and will eventually draw to the screen.

  • Set viewrootimpl as the parent of decorview

After this setting, when the subview requests to draw (requestlayout), it can always find viewrootimpl through the parent, and then theViewRootImplTo be responsible for drawing all views.
The whole calling process is as follows:

View.requestLayout -> DecorView.requestLayout -> ViewRootImpl.requestLayout

//View.java
    public void requestLayout() {
        if (mParent != null && !mParent.isLayoutRequested()) {
            mParent.requestLayout();
        }
    }

Summary

So far,ActivityFinally completed his start-up life cycle, the interface is also displayed, little love has also become a formingActivity

Although there are many middle roles, each role is indispensable

Because you need to manage the view, you create thePhoneWindow
Because we need to display different layout structures according to the theme, we create the root viewDecorView
Because we need to handle various events of view, including drawing and event distribution, we create aViewRootImpl

Everyone is busy and obedientActivity

exercises

Before class, I always like to do some exercises after learning knowledge. Today, I also bring you some problems to consolidate the knowledge.

Activity, phonewindow, decorview, viewrootimpl?

  • PhoneWindow: is the middle layer of interaction between activity and view, which helps activity manage view.
  • DecorView: is the top view of all views and the parent of all views.
  • ViewRootImpl: used to handle view related events, such as drawing and event distribution. It is also the parent of decorview.

What is the time to create the four?

  • ActivityCreated in the performlaunchactivity method and triggered at startactivity.
  • PhoneWindow, which is also created in the performlaunchactivity method, and more specifically, the attach method of the activity.
  • DecorView, created in setcontentview > phonewindow.installdecor.
  • ViewRootImpl, created in the handleresumeactivity method, and finally created through addview.

When did the view first draw?

The first drawing took place inhandleResumeActivityMethod, create theViewRootImpl, and called itssetViewmethod.

Finally, we call the requestLayout method to start the layout, measurement and rendering process.

Why does thread update UI crash?

In the trigger drawing method requestlayout, there is a checkthread method

void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

The mthread is compared with the current thread. And mthread is in theViewRootImplIt is assigned when instantiated.

So the reason for the crash is that the thread when the view is drawn to the interface (that is, the thread when the viewrootimpl is created) is not the same thread when the UI is updated.

reference resources

Android advanced decryption
These 12 questions

bye-bye

Thank you for reading. A little buddy can learn about my official account code blocks. ❤️❤️
Every day a knowledge point, add up to build a knowledge system architecture.
Here are a group of good Android friends, welcome to join ~

Recommended Today

Looking for frustration 1.0

I believe you have a basic understanding of trust in yesterday’s article. Today we will give a complete introduction to trust. Why choose rust It’s a language that gives everyone the ability to build reliable and efficient software. You can’t write unsafe code here (unsafe block is not in the scope of discussion). Most of […]