「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战」
相关文章:
Android View的绘制流程(一)-绘制流程以及Activity视图介绍
Android View的绘制流程(二)-Activity视图-DecorView
Android View的绘制流程(三)-Activity视图-WindowManager
Android View的绘制流程(四)-Activity视图-ViewRootImpl
Android View的绘制流程(五)-Measure
Android View的绘制流程(六)-Layout
Android View的绘制流程(七)-Draw
上一篇文章的Activity视图里面可以看得出,DecorView是activity窗口的根视图,每个activity都对应一个窗口window,这个窗口是PhoneWindow的实例,PhoneWindow对应的布局是DecorView,是一个FrameLayout,DecorView内部又分为两部分,一部分是ActionBar,另一部分是ContentParent,即activity在setContentView对应的布局。
DecorView的初始化
先从创建的MainActivity看,在onCreate方法中首先调用的是setContentView方法
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
MainActivity的父类是AppCompatActivity 的方法,最终会调用 AppCompatDelegateImpl 的 setContentView 方法:
// 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();
}
ensureSubDecor就是创建 subDecorView,根据主题的不同设置不同的属性,再将从 activity 传入的 id xml 布局添加到里面。在添加之前先调用 removeAllViews() 方法,确保没有其他子 View 的干扰。 可以简单看下subDecorView的实现:
private void ensureSubDecor() {
if (!this.mSubDecorInstalled) {
this.mSubDecor = this.createSubDecor();
......
}
......
}
最终会调用createSubDecor方法,这个方法就是最终的实现,代码很多,贴出来大家可以看下:
private ViewGroup createSubDecor() {
// 1、获取主题参数,进行一些设置,包括标题,actionbar 等
TypedArray 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、确保优先初始化 DecorView
this.mWindow.getDecorView();
LayoutInflater inflater = LayoutInflater.from(this.mContext);
ViewGroup subDecor = null;
// 3、根据不同的设置来对 subDecor 进行初始化
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);
}
}
// 将 subDecor 添加到 DecorView 中
this.mWindow.setContentView(subDecor);
contentView.setAttachListener(new OnAttachListener() {
public void onAttachedFromWindow() {
}
public void onDetachedFromWindow() {
AppCompatDelegateImpl.this.dismissPopups();
}
});
return subDecor;
}
}
}
上面的代码比较多,代码的主要内容,就是根据设置的主题设置不同的属性,包括标题还有actionBar,其次就是根据不同的特性初始化subDecor,并且初始化subDecor的内部View,最后把设置好的属性和初始化的内部view添加到DecorView中,添加的代码这里也贴一下:
// AppCompatDelegateImpl
this.mWindow.getDecorView();
// phoneWindow
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 生成 DecorView
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
// 这样 DecorView 就持有了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());
}
依次调用了getDecorView(),installDecor(),generateDecor(),最后return一个DecorView,DecorView是创建好了,可是创建好的东西,怎么呈现给用户呢,肯定是需要一个媒介,那么根据第一篇文章中写道的内容,那么DecorView创建完之后,是需要通过WindowMangaer来传递的,那么是如何将 View 传到 WindowManager 中呢。下一篇文章,会介绍它们的传递过程。