Activity.setcontentview () to activity.onresume ()

  • 1 setContentView(): Initializes the DecorView and does not add it to the Window
  • 2 when onResume(), the Activity is not added to the screen, onResume() will be added to the screen after, so the width and height of the View in onResume() may not be obtained
  • Since this chapter does not cover the Activity launch process, we assume that the Window, Context, and other precursors have been created

No BB, code up

The Activity of the setContentView () :

Public void setContentView(int layoutResID) {// Widnow setContentView() getWindow().setContentView(layoutResID); // Initialize ActionBar initWindowDecorActionBar(); } //getWindow returns mWindow public Window getWindow() {// The Window assignment is PhoneWindow, which is created in the attach of the Activity, We'll talk about return mWindow; } //PhoneWindow setContentView public void setContentView(int layoutResID) {//mContentView is a ViewGroup if (mContentParent == null) {//1 Initialize DecorView installDecor(); } / /.. Omit some code.. //2 Populates the layout to mContentParent mLayOutInflater.inflate (layoutResID, mContentParent); }Copy the code

1. InstallDecor

Private void installDecor() {mForceDecorInstall = false; If (mDecor == null) {// Create DecorView mDecor = generateDecor(-1); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (! mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures ! = 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } } else { mDecor.setWindow(this); } if (mContentParent == null) {// Generate mContentParent mContentParent = generateLayout(mDecor); //DecorView inherits FrameLayout protected DecorView generateDecor(int featureId) {//** omit the code to get the context ** Return new DecorView(context, featureId, this, getAttributes()); } // mContentParent generates viewgroups according to the topic and returns them. Protected ViewGroup generateLayout(DecorView decor) {//** omitted code ** int layoutResource; int features = getLocalFeatures(); If ((features & (1 << FEATURE_NO_TITLE)) == 0) {if(mIsFloating) {TypedValue res = new TypedValue(); getContext().getTheme().resolveAttribute( R.attr.dialogTitleDecorLayout, res, true); layoutResource = res.resourceId; } else if ((features & (1 << FEATURE_ACTION_BAR)) ! = 0) { layoutResource = a.getResourceId( R.styleable.Window_windowActionBarFullscreenDecorLayout, R.layout.screen_action_bar); } else {// Specify a layout file. // This layout file has a FrameLayout layoutResource = r.layout.screen_title for android:id = "@android:id/content"; }} // Add this layout to DecorView mDecor. OnResourcesLoaded (mLayoutInflater, layoutResource); //findViewById() returns FrameLayout for content in the newly added layout. ContentParent ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { throw new RuntimeException("Window couldn't find content container view"); } // return contentParent; } // Take a look at the code that adds the layout to the DecorView (this simplifies the code logic, Void onResourcesLoaded(LayoutInflater inflater {// Parse this layoutResource as View final View root = infler.inflate (layoutResource, null); // Add to the DecorView, AddView (root, 0, new viewgroup.layoutparams (MATCH_PARENT, MATCH_PARENT)); mContentRoot = (ViewGroup) root; }Copy the code

R.layout.screen_title Layout file contents

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:fitsSystemWindows="true"> <! -- Popout bar for action modes --> <ViewStub android:id="@+id/action_mode_bar_stub" 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:id="@android:id/title_container" android:layout_width="match_parent" android:layout_height="? android:attr/windowTitleSize" android:transitionName="android:title" style="? Android: attr/windowTitleBackgroundStyle "> < / FrameLayout > / / there's a id for the content of the FrameLayout, So setContentView() will add to this <FrameLayout android:id="@android:id/content" Android :layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1" android:foregroundGravity="fill_horizontal|top" android:foreground="? android:attr/windowContentOverlay" /> </LinearLayout>Copy the code

To summarize: DecorView is a FrameLayout with a content FrameLayout (mContentParent). Our setContentView() is added to this mContentParent. That is, the Activity’s default layout level is at least 2, and the DecorView wraps around the mContentParent, which wraps around our own setContentView() set View, of course, without calling the setContentView()

Look again at the 2: inflate() method

Public View inflate(@layoutres int resource, @Nullable ViewGroup root) {return inflate(resource, root, root ! = null); } // this public View inflate(@layoutRes int resource, @nullable ViewGroup root, boolean attachToRoot) { final Resources res = getContext().getResources(); View view = tryInflatePrecompiled(resource, res, root, attachToRoot); if (view ! = null) { return view; } XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); Public View inflate(XmlPullParser Parser, @nullable ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { final Context inflaterContext = mContext; Final AttributeSet attrs = xml. asAttributeSet(parser); View result = root; Try {// Check for START_TAG and raise advanceToRootNode(parser); final String name = parser.getName(); / / handle the merge tag if (TAG_MERGE equals (name)) {/ / here you can see a knowledge: < merge > tag attachRoot must be true, otherwise it will throw exceptions if (root = = null | |! attachToRoot) { throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } rInflate(parser, root, inflaterContext, attrs, false); } else {// Create View final View temp = createViewFromTag(root, name, inflaterContext, attrs); // Set LayoutParams viewGroup. LayoutParams params = null; if (root ! = null) { params = root.generateLayoutParams(attrs); if (! attachToRoot) { temp.setLayoutParams(params); }} // Fill the child View, which is a deep traversal process rInflateChildren(Parser, temp, attrs, true); // key!! Add a View to root. Add a View to mContentParent if (root! = null && attachToRoot) { root.addView(temp, params); } if (root == null || ! attachToRoot) { result = temp; }}}catch(Exception e){return mContentParent return result; }}Copy the code

At this point, after the above code is done, there is this result:

  • SetContentView () inside onCreate() for the Activity
  • SetContentView (lauoutID) layoutID is resolved to a View
  • 3 this View is added to the mContentParent, which is equivalent to adding it to the DecorView. Note that the View is added to the DecorView, not to the Window

The ActivityThread handleResumeActivity

Public void handleResumeActivity(IBinder Token, Boolean finalStateRequest, Boolean isForward,String Reason) {ActivityClientRecord final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); Final Activity A = r.activity; if (r.window == null && ! A.finished &&willBeVisible) {// call window. R.window = R.activity. GetWindow () created in activity.atttach (); // DecorView, View decor = r.window.getDecorView(); // Set decor. SetVisibility (view.invisible) to INVISIBLE. WindowManager ViewManager wm = a.getwinDowManager (); / / remove the LayoutParams WindowManager. = LayoutParams l truly indow. GetAttributes (); a.mDecor = decor; / / Window types are: WindowManager. LayoutParams. TYPE_BASE_APPLICATION l.t ype = WindowManager. LayoutParams. TYPE_BASE_APPLICATION;  l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { if (! a.mWindowAdded) { a.mWindowAdded = true; // Add DecorView to Window wm.addView(decor, L); } else { a.onWindowAttributesChanged(l); }}}... If (state Richard armitage ctivity. MVisibleFromClient) {/ / make DecorView visible state Richard armitage ctivity. MakeVisible (); }... }Copy the code

The above code consists of three steps:

  • 1 Remove the DecorView and make the DecorView invisible
  • 2 Take out the Window and add the DecorView to the Window
  • 3 Make the DecorView visible after the addition

Look at the code that adds a DecorView to the Window :wm.addView(decor, L), which is implemented under WindowManagerImpl:

@Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); //mGlobal is WindowManagerGlobal mglobal.addView (View, params, McOntext.getdisplay (), mParentWindow); } //WindowManagerGlobal addView, Public void addView(View View, ViewGroup.LayoutParams params, Display Display, Window parentWindow) {.... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; . ViewRootImpl root; synchronized (mLock) { .... // Create ViewRootImpl root = new ViewRootImpl(view.getContext(), display); // Set the layout parameter view.setLayoutParams(wparams); Mviews.add (view); mRoots.add(root); mParams.add(wparams); Try {// Add View to ViewRootImpl. Note that this View is a DecorView, i.e., the top-level View root.setView(View, wparams, null); } catch (RuntimeException e) { if (index >= 0) { removeViewLocked(index, true); } throw e; }} // Look at viewrootimpl.setView (), Stick at the relevant thread code public void setView (View View, WindowManager. LayoutParams attrs. View panelParentView) {synchronized (this) {if (mView == null) {// Save View mView = View; . // mark as added mAdded = true; . RequestLayout (); // Trigger a layout. This method is the start of the View system update. . // Specify the parent of the DecorView as view.assignparent (this); . } //View assignParent() void assignParent(ViewParent) {if (mParent == null) {// save mParent = parent; } else if (parent == null) { mParent = null; } else {// If parent is already present, Throw new RuntimeException(" View "+ this +" being added, but" + " it already has a parent"); }}Copy the code

summary

  • 1 call WindowManager. AddView (decor), its implementation is WindowManagerImpl addView (decor)
  • 2 call WindowManagerGlobal. AddView ()
  • SetView () saves the decorView as its member variable, triggers requestLayout(), and sets the parent of the decorView to ViewRoorImpl

Now that our View has been added to the Window and requestLayout() is triggered once, let’s look at it:

public void requestLayout() { if (! MHandlingLayoutInLayoutRequest) {/ / as a first step, check the thread checkThread (); // Step 2, refresh the mLayoutRequested = true; // Update scheduleTraversals(); Void checkThread() {if (mThread! = Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); }} void scheduleTraversals() {if (! MTraversalScheduled) {// Refresh the traversalscheduled marker mTraversalScheduled = true; MTraversalBarrier = mhandler.getlooper ().getQueue().postsyncBarrier (); // Add asynchronous messages. MChoreographer is just a Handler, Eventually executes the mTraversalRunnable mChoreographer. PostCallback (Choreographer. CALLBACK_TRAVERSAL mTraversalRunnable, null); . }} //mTraversalRunnable final class TraversalRunnable implements Runnable {@override public void run() doTraversal(); }} void doTraversal() {if (mTraversalScheduled) {}} void doTraversal() {mTraversalScheduled = false; // Remove the synchronization barrier mhandler.getLooper ().getQueue().removesyncBarrier (mTraversalBarrier); // Here is the point, performTraversals(); . }} private void performTraversals() private void performTraversals() private void performTraversals() // Negotiate measureHierarchy... / / measuring performMeaure (); . / / layout performLayout (); . / / draw performDraw (); }Copy the code

summary After we after ViewRootImpl. RequestLayout (), the contents of the View is drawn on the screen, then let the decor, so he saw on the screen of the setContentView () to set the layout, is not familiar to ViewRootImpl, Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler

conclusion

  • 1 Activity.setContView(layoutId) initializes the DecorView, which is FrameLayout; Initialize mContentParent, which is a ViewGroup
  • 2 When mContentParent is initialized, the system layout will be loaded according to the theme, and there will be a FrameLayout with the id of Content
  • 3 ActivityThread. HandleResumeActivity () will get WindowManager, then add DecorView to the Window
  • 4 The steps to add a DecorView, which are eventually implemented through Windows ManagerGlobal, create the ViewRootImpl and then call the setView() function
  • The setView function assigns the parent of the view to ViewRootImpl and triggers requestLayout().
  • RequestLayout () is implemented by Posting an asynchronous message and eventually calling its own performTraversals() to render the measured layout of the View