“This is the 11th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
As you can see from the Activity view in the previous article, a DecorView is the root view of the Activity window. Each Activity corresponds to a window that is an instance of a PhoneWindow. The layout of a PhoneWindow is DecirView. Is a FrameLayout, and inside the DecorView there are two parts: the ActionBar and the ContentParent, which is the layout of the activity in the setContentView.
DecorView initialization
In the onCreate method, the setContentView method is called first
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
Copy the code
The parent class of MainActivity is a method for AppCompatActivity, which will eventually call the setContentView method of AppCompatDelegateImpl:
// AppCompatDelegateImpl
public void setContentView(int resId) {
this.ensureSubDecor();
ViewGroup contentParent = (ViewGroup)this.mSubDecor.findViewById(16908290);
contentParent.removeAllViews();
LayoutInflater.from(this.mContext).inflate(resId, contentParent);
this.mOriginalWindowCallback.onContentChanged();
}
Copy the code
EnsureSubDecor is the creation of subDecorView, setting different properties based on the theme, and adding id XML layout from the activity. Call the removeAllViews() method before adding to make sure there are no other child views interfering. A quick look at the subDecorView implementation:
private void ensureSubDecor() { if (! this.mSubDecorInstalled) { this.mSubDecor = this.createSubDecor(); . }... }Copy the code
Finally, the createSubDecor method is called. This method is the final implementation.
Private ViewGroup createSubDecor() {// 1. Actionbar TypedArray, such as a = this. MContext. ObtainStyledAttributes (styleable. AppCompatTheme); if (! a.hasValue(styleable.AppCompatTheme_windowActionBar)) { a.recycle(); throw new IllegalStateException("You need to use a Theme.AppCompat theme (or descendant) with this activity."); } else { if (a.getBoolean(styleable.AppCompatTheme_windowNoTitle, false)) { this.requestWindowFeature(1); } else if (a.getBoolean(styleable.AppCompatTheme_windowActionBar, false)) { this.requestWindowFeature(108); } if (a.getBoolean(styleable.AppCompatTheme_windowActionBarOverlay, false)) { this.requestWindowFeature(109); } if (a.getBoolean(styleable.AppCompatTheme_windowActionModeOverlay, false)) { this.requestWindowFeature(10); } this.mIsFloating = a.getBoolean(styleable.AppCompatTheme_android_windowIsFloating, false); a.recycle(); / / 2, to ensure priority initialization DecorView enclosing mWindow. GetDecorView (); LayoutInflater inflater = LayoutInflater.from(this.mContext); ViewGroup subDecor = null; // 3. Initializes subDecor according to different Settings if (! this.mWindowNoTitle) { if (this.mIsFloating) { subDecor = (ViewGroup)inflater.inflate(layout.abc_dialog_title_material, (ViewGroup)null); this.mHasActionBar = this.mOverlayActionBar = false; } else if (this.mHasActionBar) { TypedValue outValue = new TypedValue(); this.mContext.getTheme().resolveAttribute(attr.actionBarTheme, outValue, true); Object themedContext; if (outValue.resourceId ! = 0) { themedContext = new ContextThemeWrapper(this.mContext, outValue.resourceId); } else { themedContext = this.mContext; } subDecor = (ViewGroup)LayoutInflater.from((Context)themedContext).inflate(layout.abc_screen_toolbar, (ViewGroup)null); this.mDecorContentParent = (DecorContentParent)subDecor.findViewById(id.decor_content_parent); this.mDecorContentParent.setWindowCallback(this.getWindowCallback()); if (this.mOverlayActionBar) { this.mDecorContentParent.initFeature(109); } if (this.mFeatureProgress) { this.mDecorContentParent.initFeature(2); } if (this.mFeatureIndeterminateProgress) { this.mDecorContentParent.initFeature(5); } } } else { if (this.mOverlayActionMode) { subDecor = (ViewGroup)inflater.inflate(layout.abc_screen_simple_overlay_action_mode, (ViewGroup)null); } else { subDecor = (ViewGroup)inflater.inflate(layout.abc_screen_simple, (ViewGroup)null); } if (VERSION.SDK_INT >= 21) { ViewCompat.setOnApplyWindowInsetsListener(subDecor, new OnApplyWindowInsetsListener() { public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { int top = insets.getSystemWindowInsetTop(); int newTop = AppCompatDelegateImpl.this.updateStatusGuard(top); if (top ! = newTop) { insets = insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), newTop, insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()); } return ViewCompat.onApplyWindowInsets(v, insets); }}); } else { ((FitWindowsViewGroup)subDecor).setOnFitSystemWindowsListener(new OnFitSystemWindowsListener() { public void onFitSystemWindows(Rect insets) { insets.top = AppCompatDelegateImpl.this.updateStatusGuard(insets.top); }}); } } if (subDecor == null) { throw new IllegalArgumentException("AppCompat does not support the current theme features: { windowActionBar: " + this.mHasActionBar + ", windowActionBarOverlay: " + this.mOverlayActionBar + ", android:windowIsFloating: " + this.mIsFloating + ", windowActionModeOverlay: " + this.mOverlayActionMode + ", windowNoTitle: " + this.mWindowNoTitle + " }"); } else { if (this.mDecorContentParent == null) { this.mTitleView = (TextView)subDecor.findViewById(id.title); } ViewUtils.makeOptionalFitsSystemWindows(subDecor); ContentFrameLayout contentView = (ContentFrameLayout)subDecor.findViewById(id.action_bar_activity_content); ViewGroup windowContentView = (ViewGroup)this.mWindow.findViewById(16908290); if (windowContentView ! = null) { while(windowContentView.getChildCount() > 0) { View child = windowContentView.getChildAt(0); windowContentView.removeViewAt(0); contentView.addView(child); } windowContentView.setId(-1); contentView.setId(16908290); if (windowContentView instanceof FrameLayout) { ((FrameLayout)windowContentView).setForeground((Drawable)null); }} / / will be added to the DecorView subDecor enclosing mWindow. The setContentView (subDecor); contentView.setAttachListener(new OnAttachListener() { public void onAttachedFromWindow() { } public void onDetachedFromWindow() { AppCompatDelegateImpl.this.dismissPopups(); }}); return subDecor; }}}Copy the code
The above code is more, the main content of the code, is to set different properties according to the theme set, This includes the title and actionBar, and then the subDecor is initialized for different features and the interior View is initialized. Finally, add the set property and the interior View to the DecorView.
// AppCompatDelegateImpl this.mWindow.getDecorView(); // phoneWindow public final View getDecorView() { if (mDecor == null || mForceDecorInstall) { installDecor(); } return mDecor; } private void installDecor() { mForceDecorInstall = false; // Generate DecorView mDecor = generateDecor(-1); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (! mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures ! = 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); }} else {// DecorView has window mDecor. SetWindow (this); }... } protected DecorView generateDecor(int featureId) { // System process doesn't have application context and in that case we need to directly use // the context we have. Otherwise we want the application context, so we don't cling to the // activity. Context context; if (mUseDecorContext) { Context applicationContext = getContext().getApplicationContext(); if (applicationContext == null) { context = getContext(); } else { context = new DecorContext(applicationContext, getContext()); if (mTheme ! = -1) { context.setTheme(mTheme); } } } else { context = getContext(); } return new DecorView(context, featureId, this, getAttributes()); }Copy the code
Call getDecorView(),installDecor(),generateDecor(), and finally return a DecorView. According to the first article, after the DecorView is created, it needs to be passed through the WindowMangaer, so how to pass the View to the WindowManager? In the next article, you’ll see how they are delivered.