本文主要是介绍Activity中setContentView浅析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
protected void onCreate(final Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);
}
setContentView()方法会将我们的视图设置到哪儿去了?
public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();
}
Activity会调用当前Activity的Window的setContentView()方法,而Window类是一个抽象类,唯一实现类PhoneWindow。
PhoneWindwo对象在Activity中的attach()方法中创建。
final void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window) {attachBaseContext(context);mFragments.attachHost(null /*parent*/);mWindow = new PhoneWindow(this, window);mWindow.setWindowControllerCallback(this);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);//......
}
那我们接着看PhoneWindow的setContentView()方法。
public void setContentView(int layoutResID) {if (mContentParent == null) {installDecor();} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,getContext());transitionTo(newScene);} else {mLayoutInflater.inflate(layoutResID, mContentParent);}mContentParent.requestApplyInsets();final Callback cb = getCallback();if (cb != null && !isDestroyed()) {cb.onContentChanged();}
}
当我们第一此setContentView()时,mContentParent为空,会调用installDecor()方法做些初始化工作。然后再将我们setContentView里的View加载到mContentParent上面去。
mLayoutInflater.inflate(layoutResID, mContentParent)
来看看installDecor()做了什么伟大的事情:
private DecorView mDecor;private ViewGroup mContentParent;private ViewGroup mContentRoot;private void installDecor() {if (mDecor == null) {mDecor = generateDecor();mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);}}if (mContentParent == null) {mContentParent = generateLayout(mDecor);// Set up decor part of UI to ignore fitsSystemWindows if appropriate.mDecor.makeOptionalFitsSystemWindows();//....}
}
mDecor是DecorView类对象,而DecorView继承自FrameLayout,generateDecor()方法就是初始化创建一个空的FrameLayout。来看generateLayout()方法是怎样初始化我们需要的mContentParent的:
protected ViewGroup generateLayout(DecorView decor) { TypedArray a = getWindowStyle();if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {requestFeature(FEATURE_NO_TITLE);} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {requestFeature(FEATURE_ACTION_BAR);}if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {requestFeature(FEATURE_ACTION_BAR_OVERLAY);}//....if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {layoutResource = R.layout.screen_swipe_dismiss;} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {if (mIsFloating) {TypedValue res = new TypedValue();getContext().getTheme().resolveAttribute(R.attr.dialogTitleIconsDecorLayout, res, true);layoutResource = res.resourceId;} else {layoutResource = R.layout.screen_title_icons;}removeFeature(FEATURE_ACTION_BAR);} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {layoutResource = R.layout.screen_progress;} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {}//.....int layoutResource;//.....View in = mLayoutInflater.inflate(layoutResource, null);decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));mContentRoot = (ViewGroup) in;ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//.....return contentParent;}
generateLayout()方法会根据我们Acivity主题样式,选择加载不同的系统布局资源,并将该视图添加到DecorView中去。
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
无论选择哪一个布局资源里面都一个id名为content的FrameLayout。再从该布局中找到我们需要的contentParent。
(ViewGroup)findViewById(ID_ANDROID_CONTENT);
最后返回contentParent,将setContentView()中的视图加载到mContentParent上去。
这篇关于Activity中setContentView浅析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!