setContentView()可以说是大家最熟悉的方法了,Activity中设置xml布局调用。
下面看看源码中具体如何设置根布局的。
首先调用父类AppCompatActivity.setContentView()
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
public AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, this);
}
return mDelegate;
}
AppCompatDelegate是个抽象类
AppCompatDelegate.create()
public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
return new AppCompatDelegateImpl(activity, activity.getWindow(), callback);
}
实现类是AppCompatDelegateImpl,看看构造方法
AppCompatDelegateImpl(Context context, Window window, AppCompatCallback callback) {
mContext = context;
mWindow = window;
mAppCompatCallback = callback;
mOriginalWindowCallback = mWindow.getCallback();
if (mOriginalWindowCallback instanceof AppCompatWindowCallback) {
throw new IllegalStateException(
"AppCompat has already installed itself into the Window");
}
mAppCompatWindowCallback = new AppCompatWindowCallback(mOriginalWindowCallback);
//设置回调
mWindow.setCallback(mAppCompatWindowCallback);
//Window背景色
final TintTypedArray a = TintTypedArray.obtainStyledAttributes(
context, null, sWindowBackgroundStyleable);
final Drawable winBg = a.getDrawableIfKnown(0);
if (winBg != null) {
mWindow.setBackgroundDrawable(winBg);
}
a.recycle();
}
setContentView()最终调用到了代理类AppCompatDelegateImpl.setContentView(),这里是重点
public void setContentView(int resId) {
//创建DecorView
ensureSubDecor();
//id为content的FrameLayout
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
//移除content上所有view
contentParent.removeAllViews();
//加载我们的xml布局到content
LayoutInflater.from(mContext).inflate(resId, contentParent);
//回调
mOriginalWindowCallback.onContentChanged();
}
AppCompatDelegateImpl.ensureSubDecor()
private void ensureSubDecor() {
if (!mSubDecorInstalled) {
//创建DecorView
mSubDecor = createSubDecor();
//ActionBar title
CharSequence title = getTitle();
if (!TextUtils.isEmpty(title)) {
if (mDecorContentParent != null) {
mDecorContentParent.setWindowTitle(title);
} else if (peekSupportActionBar() != null) {
peekSupportActionBar().setWindowTitle(title);
} else if (mTitleView != null) {
mTitleView.setText(title);
}
}
applyFixedSizeWindow();
//创建DecorView回调
onSubDecorInstalled(mSubDecor);
mSubDecorInstalled = true;
//menu
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!mIsDestroyed && (st == null || st.menu == null)) {
invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR);
}
}
}
AppCompatDelegateImpl.createSubDecor()
...
final LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup subDecor = null;
//有无title
if (!mWindowNoTitle) {
//Activity弹框形式出现
if (mIsFloating) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_dialog_title_material, null);
}else if (mHasActionBar) {//有ActionBar
subDecor = (ViewGroup) LayoutInflater.from(themedContext)
.inflate(R.layout.abc_screen_toolbar, null);
mDecorContentParent = (DecorContentParent) subDecor
.findViewById(R.id.decor_content_parent);
}
} else {
if (mOverlayActionMode) {//覆盖模式
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_screen_simple_overlay_action_mode, null);
} else {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
}
}
//将原有Window的view迁移到我们的ContentView
final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
R.id.action_bar_activity_content);
final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
if (windowContentView != null) {
while (windowContentView.getChildCount() > 0) {
final View child = windowContentView.getChildAt(0);
windowContentView.removeViewAt(0);
contentView.addView(child);
}
//设置id
windowContentView.setId(View.NO_ID);
contentView.setId(android.R.id.content);
if (windowContentView instanceof FrameLayout) {
((FrameLayout) windowContentView).setForeground(null);
}
}
//DecorView关联到window
mWindow.setContentView(subDecor);
return subDecor;
mWindow.setContentView(subDecor)
window在Activity中初始化,实现类是PhoneWindow
Activity.attach()
final void attach(...){
mWindow = new PhoneWindow(this, window, activityConfigCallback);
}
PhoneWindow.setContentView()
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
mContentParent.addView(view, params);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
createSubDecor()方法根据不同的配置创建不同样式的DecorView,并调用PhoneWindow.setContentView()关联到window。
总结:setContentView()会调用到代理类AppCompatDelegateImpl.setContentView(),这里会先创建真正的顶层布局DecorView,按需创建menu,ActionBar,并添加id为content的FrameLayout子view,然后LayoutInflater将我们设置的xml布局解析成View树,最后添加到content。
![](https://img.haomeiwen.com/i7581259/48c0700f0c37f9d5.png)
网友评论