源码分析setContentView加载布局文件的过程
2017-07-12 09:13
411 查看
我们都知道通过setContentView方法将xml布局文件加载到Activity中,然后屏幕才能显示出xml中定义的view。在整个过程中,无须做太多的操作,屏幕就能显示出正常的内容。现在我们从源码的角度来看看系统到底帮我们处理了哪些操作。
首先,进入setContentView方法中查看:
Activity.java:
里面通过getWindow()获得的对象来setContentView。getWindow()返回是Window对象,它是一个抽象类。为了获取它的实现类,我们可以打印它的类信息,如下:
在Activity中运行后,得到打印结果信息:
现在我们知道真正发挥作用的是PhoneWindow类。进入该类中,查看setContentView方法:
PhoneWindow.java
首先判断mContentParent为null时,执行installDecor()方法,我们稍后分析mContentParent是什么,先分析installDecor()方法,进入该方法中:
PhoneWindow.java
这里面的代码比较多,我们逐个分析:首先是判断mDecor 对象为null时,执行了方法generateDecor(),如下:
该方法用来实例化一个DecorView 对象,PhoneWindow中对该类的解释是窗口的顶层视图。继续执行代码,判断 mContentParent 为null时,调用方法generateLayout(mDecor),将其初始化。
PhoneWindow.java:
上面的方法中可知,首先读取的Window的基本属性,包括是否设置状态栏,是否设置标题栏,是否设置状态栏和导航栏颜色等等。然后根据不同的features 来加载系统中对应的xml布局资源。并且将该布局资源填充到view中,然后将该View添加到mDecor里面。最后将布局文件中的R.id.content的view作为contentParent并返回。这样 mContentParent就获得了初始化对象,就是R.id.content对应的View。
这里我们在回到方法setContentView中,完成了 installDecor()方法后,我们接下来将执行mLayoutInflater.inflate(layoutResID, mContentParent),通过mLayoutInflater将传进来的布局Id加载到父容器mContentParent中,到这里就将布局添加到Activity中了。
总结:
1.Activity中执行setContentView时,内部调用的是PhoneWindow中的setContentView方法。而PhoneWindow中的setContentView方法里,有分别调用了installDecor方法,mLayoutInflater.inflate(layoutResID, mContentParent),和回调方法cb.onContentChanged()。
2.PhoneWindow中的installDecor方法,主要是初始化了DecorView对象和mContentParent父容器,让后设置窗口背景颜色和进入/退出是的动画属性。
3.installDecor方法中,执行的generateLayout(mDecor)方法,主要是设置系统默认属性,如:状态栏,设置标题栏,设置状态栏和导航栏颜色等等。然后选择加载系统中的布局文件到DecorView容器中,其中R.id.content的view作为mContentParent的父容器,然后返回mContentParent。
通过上面可以知道,如果在Activity中想要执行requestWindowFeature(Window.FEATURE_NO_TITLE)的方法,那么则需要在setContentView方法之前使用,否则无效。
那么在Activity加载完布局之后,所有显示的层级结构可以用下图表示(图片来自网络):
首先,进入setContentView方法中查看:
Activity.java:
public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }
里面通过getWindow()获得的对象来setContentView。getWindow()返回是Window对象,它是一个抽象类。为了获取它的实现类,我们可以打印它的类信息,如下:
Log.i("yumf","getWindow():" + getWindow());
在Activity中运行后,得到打印结果信息:
getWindow():com.android.internal.policy.PhoneWindow@5c4bc31
现在我们知道真正发挥作用的是PhoneWindow类。进入该类中,查看setContentView方法:
PhoneWindow.java
@Override public void setContentView(int layoutResID) { // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. 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(); } }
首先判断mContentParent为null时,执行installDecor()方法,我们稍后分析mContentParent是什么,先分析installDecor()方法,进入该方法中:
PhoneWindow.java
private void installDecor() { if (mDecor == null) { mDecor = generateDecor(); //实例化窗口的顶层视图 mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } } //mContentParent 存放窗口内容的视图,可以是mDecor 或者是子mDecor 内容 if (mContentParent == null) { mContentParent = generateLayout(mDecor); // Set up decor part of UI to ignore fitsSystemWindows if appropriate. mDecor.makeOptionalFitsSystemWindows(); final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById( R.id.decor_content_parent); if (decorContentParent != null) { mDecorContentParent = decorContentParent; mDecorContentParent.setWindowCallback(getCallback()); if (mDecorContentParent.getTitle() == null) { mDecorContentParent.setWindowTitle(mTitle); } final int localFeatures = getLocalFeatures(); for (int i = 0; i < FEATURE_MAX; i++) { if ((localFeatures & (1 << i)) != 0) { mDecorContentParent.initFeature(i); } } mDecorContentParent.setUiOptions(mUiOptions); if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 || (mIconRes != 0 && !mDecorContentParent.hasIcon())) { mDecorContentParent.setIcon(mIconRes); } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 && mIconRes == 0 && !mDecorContentParent.hasIcon()) { mDecorContentParent.setIcon( getContext().getPackageManager().getDefaultActivityIcon()); mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK; } if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 || (mLogoRes != 0 && !mDecorContentParent.hasLogo())) { mDecorContentParent.setLogo(mLogoRes); } // Invalidate if the panel menu hasn't been created before this. // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu // being called in the middle of onCreate or similar. // A pending invalidation will typically be resolved before the posted message // would run normally in order to satisfy instance state restoration. PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) { invalidatePanelMenu(FEATURE_ACTION_BAR); } } else { mTitleView = (TextView)findViewById(R.id.title); if (mTitleView != null) { mTitleView.setLayoutDirection(mDecor.getLayoutDirection()); if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { View titleContainer = findViewById( R.id.title_container); if (titleContainer != null) { titleContainer.setVisibility(View.GONE); } else { mTitleView.setVisibility(View.GONE); } if (mContentParent instanceof FrameLayout) { ((FrameLayout)mContentParent).setForeground(null); } } else { mTitleView.setText(mTitle); } } } if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) { mDecor.setBackgroundFallback(mBackgroundFallbackResource); } // Only inflate or create a new TransitionManager if the caller hasn't // already set a custom one. if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) { if (mTransitionManager == null) { final int transitionRes = getWindowStyle().getResourceId( R.styleable.Window_windowContentTransitionManager, 0); if (transitionRes != 0) { final TransitionInflater inflater = TransitionInflater.from(getContext()); mTransitionManager = inflater.inflateTransitionManager(transitionRes, mContentParent); } else { mTransitionManager = new TransitionManager(); } } mEnterTransition = getTransition(mEnterTransition, null, R.styleable.Window_windowEnterTransition); mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION, R.styleable.Window_windowReturnTransition); mExitTransition = getTransition(mExitTransition, null, R.styleable.Window_windowExitTransition); mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION, R.styleable.Window_windowReenterTransition); mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null, R.styleable.Window_windowSharedElementEnterTransition); mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition, USE_DEFAULT_TRANSITION, R.styleable.Window_windowSharedElementReturnTransition); mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null, R.styleable.Window_windowSharedElementExitTransition); mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition, USE_DEFAULT_TRANSITION, R.styleable.Window_windowSharedElementReenterTransition); if (mAllowEnterTransitionOverlap == null) { mAllowEnterTransitionOverlap = getWindowStyle().getBoolean( R.styleable.Window_windowAllowEnterTransitionOverlap, true); } if (mAllowReturnTransitionOverlap == null) { mAllowReturnTransitionOverlap = getWindowStyle().getBoolean( R.styleable.Window_windowAllowReturnTransitionOverlap, true); } if (mBackgroundFadeDurationMillis < 0) { mBackgroundFadeDurationMillis = getWindowStyle().getInteger( R.styleable.Window_windowTransitionBackgroundFadeDuration, DEFAULT_BACKGROUND_FADE_DURATION_MS); } if (mSharedElementsUseOverlay == null) { mSharedElementsUseOverlay = getWindowStyle().getBoolean( R.styleable.Window_windowSharedElementsUseOverlay, true); } } } }
这里面的代码比较多,我们逐个分析:首先是判断mDecor 对象为null时,执行了方法generateDecor(),如下:
protected DecorView generateDecor() { return new DecorView(getContext(), -1); }
该方法用来实例化一个DecorView 对象,PhoneWindow中对该类的解释是窗口的顶层视图。继续执行代码,判断 mContentParent 为null时,调用方法generateLayout(mDecor),将其初始化。
PhoneWindow.java:
protected ViewGroup generateLayout(DecorView decor) { // Apply data from current theme. TypedArray a = getWindowStyle(); //读取当前Window的属性样式 if (false) { System.out.println("From style:"); String s = "Attrs:"; for (int i = 0; i < R.styleable.Window.length; i++) { s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "=" + a.getString(i); } System.out.println(s); } //窗口是否浮动,用户Dialog窗口是否浮动,是否显示在布局中间 mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false); int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) & (~getForcedWindowFlags()); if (mIsFloating) { setLayout(WRAP_CONTENT, WRAP_CONTENT); setFlags(0, flagsToUpdate); } else { setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); } //窗口是否支持标题栏 if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) { requestFeature(FEATURE_NO_TITLE); } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) { // Don't allow an action bar if there is no title. requestFeature(FEATURE_ACTION_BAR); } //ActionBar导航栏是否不占布局空间叠加显示在当前窗口之上 if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) { requestFeature(FEATURE_ACTION_BAR_OVERLAY); } if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) { requestFeature(FEATURE_ACTION_MODE_OVERLAY); } if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) { requestFeature(FEATURE_SWIPE_TO_DISMISS); } //是否支持当前Activity中全屏 if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) { setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags())); } if (a.getBoolean(R.styleable.Window_windowTranslucentStatus, false)) { setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS & (~getForcedWindowFlags())); } if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation, false)) { setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION & (~getForcedWindowFlags())); } if (a.getBoolean(R.styleable.Window_windowOverscan, false)) { setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags())); } if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags())); } if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch, getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB)) { setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags())); } a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor); a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor); if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) { if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedWidthMajor, mFixedWidthMajor); } if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) { if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedWidthMinor, mFixedWidthMinor); } if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) { if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedHeightMajor, mFixedHeightMajor); } if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) { if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedHeightMinor, mFixedHeightMinor); } if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) { requestFeature(FEATURE_CONTENT_TRANSITIONS); } if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) { requestFeature(FEATURE_ACTIVITY_TRANSITIONS); } final Context context = getContext(); final int targetSdk = context.getApplicationInfo().targetSdkVersion; final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB; final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP; final boolean targetHcNeedsOptions = context.getResources().getBoolean( R.bool.target_honeycomb_needs_options_menu); final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE); if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) { setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE); } else { setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE); } // Non-floating windows on high end devices must put up decor beneath the system bars and // therefore must know about visibility changes of those. if (!mIsFloating && ActivityManager.isHighEndGfx()) { if (!targetPreL && a.getBoolean( R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) { setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags()); } } //是否需要这时状态栏的颜色 if (!mForcedStatusBarColor) { mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000); } //是否设置导航栏的颜色 if (!mForcedNavigationBarColor) { mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000); } if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) { decor.setSystemUiVisibility( decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { if (a.getBoolean( R.styleable.Window_windowCloseOnTouchOutside, false)) { setCloseOnTouchOutsideIfNotSet(true); } } WindowManager.LayoutParams params = getAttributes(); if (!hasSoftInputMode()) { params.softInputMode = a.getInt( R.styleable.Window_windowSoftInputMode, params.softInputMode); } if (a.getBoolean(R.styleable.Window_backgroundDimEnabled, mIsFloating)) { /* All dialogs should have the window dimmed */ if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) { params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; } if (!haveDimAmount()) { params.dimAmount = a.getFloat( android.R.styleable.Window_backgroundDimAmount, 0.5f); } } //是否设置Activity中的动画效果 if (params.windowAnimations == 0) { params.windowAnimations = a.getResourceId( R.styleable.Window_windowAnimationStyle, 0); } // The rest are only done if this window is not embedded; otherwise, // the values are inherited from our container. if (getContainer() == null) { if (mBackgroundDrawable == null) { if (mBackgroundResource == 0) { mBackgroundResource = a.getResourceId( R.styleable.Window_windowBackground, 0); } if (mFrameResource == 0) { mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0); } mBackgroundFallbackResource = a.getResourceId( R.styleable.Window_windowBackgroundFallback, 0); if (false) { System.out.println("Background: " + Integer.toHexString(mBackgroundResource) + " Frame: " + Integer.toHexString(mFrameResource)); } } mElevation = a.getDimension(R.styleable.Window_windowElevation, 0); mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false); mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT); } //根据属性来初始化不同的布局资源id int layoutResource; int features = getLocalFeatures(); // System.out.println("Features: 0x" + Integer.toHexString(features)); 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; } // XXX Remove this once action bar supports these features. removeFeature(FEATURE_ACTION_BAR); // System.out.println("Title Icons!"); } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0 && (features & (1 << FEATURE_ACTION_BAR)) == 0) { // Special case for a window with only a progress bar (and title). // XXX Need to have a no-title version of embedded windows. layoutResource = R.layout.screen_progress; // System.out.println("Progress!"); } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { // Special case for a window with a custom title. // If the window is floating, we need a dialog layout if (mIsFloating) { TypedValue res = new TypedValue(); getContext().getTheme().resolveAttribute( R.attr.dialogCustomTitleDecorLayout, res, true); layoutResource = res.resourceId; } else { layoutResource = R.layout.screen_custom_title; } // XXX Remove this once action bar supports these features. removeFeature(FEATURE_ACTION_BAR); } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) { // If no other features and not embedded, only need a title. // If the window is floating, we need a dialog layout 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 { layoutResource = R.layout.screen_title; } // System.out.println("Title!"); } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) { layoutResource = R.layout.screen_simple_overlay_action_mode; } else { // Embedded, so no decoration is needed. layoutResource = R.layout.screen_simple; // System.out.println("Simple!"); } mDecor.startChanging(); //通过布局添加器获取layoutResource的布局 View in = mLayoutInflater.inflate(layoutResource, null); //将该布局添加到decor中,这里PhoneWindow中的DecorView就添加了布局 decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); mContentRoot = (ViewGroup) in; //通过R.id.content,找到contentParent 对象 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { throw new RuntimeException("Window couldn't find content container view"); } if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { ProgressBar progress = getCircularProgressBar(false); if (progress != null) { progress.setIndeterminate(true); } } if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) { registerSwipeCallbacks(); } //设置窗口背景 if (getContainer() == null) { final Drawable background; if (mBackgroundResource != 0) { background = getContext().getDrawable(mBackgroundResource); } else { background = mBackgroundDrawable; } mDecor.setWindowBackground(background); final Drawable frame; if (mFrameResource != 0) { frame = getContext().getDrawable(mFrameResource); } else { frame = null; } mDecor.setWindowFrame(frame); mDecor.setElevation(mElevation); mDecor.setClipToOutline(mClipToOutline); if (mTitle != null) { setTitle(mTitle); } if (mTitleColor == 0) { mTitleColor = mTextColor; } setTitleColor(mTitleColor); } mDecor.finishChanging(); return contentParent; }
上面的方法中可知,首先读取的Window的基本属性,包括是否设置状态栏,是否设置标题栏,是否设置状态栏和导航栏颜色等等。然后根据不同的features 来加载系统中对应的xml布局资源。并且将该布局资源填充到view中,然后将该View添加到mDecor里面。最后将布局文件中的R.id.content的view作为contentParent并返回。这样 mContentParent就获得了初始化对象,就是R.id.content对应的View。
这里我们在回到方法setContentView中,完成了 installDecor()方法后,我们接下来将执行mLayoutInflater.inflate(layoutResID, mContentParent),通过mLayoutInflater将传进来的布局Id加载到父容器mContentParent中,到这里就将布局添加到Activity中了。
总结:
1.Activity中执行setContentView时,内部调用的是PhoneWindow中的setContentView方法。而PhoneWindow中的setContentView方法里,有分别调用了installDecor方法,mLayoutInflater.inflate(layoutResID, mContentParent),和回调方法cb.onContentChanged()。
2.PhoneWindow中的installDecor方法,主要是初始化了DecorView对象和mContentParent父容器,让后设置窗口背景颜色和进入/退出是的动画属性。
3.installDecor方法中,执行的generateLayout(mDecor)方法,主要是设置系统默认属性,如:状态栏,设置标题栏,设置状态栏和导航栏颜色等等。然后选择加载系统中的布局文件到DecorView容器中,其中R.id.content的view作为mContentParent的父容器,然后返回mContentParent。
通过上面可以知道,如果在Activity中想要执行requestWindowFeature(Window.FEATURE_NO_TITLE)的方法,那么则需要在setContentView方法之前使用,否则无效。
那么在Activity加载完布局之后,所有显示的层级结构可以用下图表示(图片来自网络):
相关文章推荐
- Android布局文件的加载过程分析:Activity.setContentView()源码分析
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起(写的很好,这个不是从启动app说的,说的是UI是怎么绘制的)
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- 【转载】Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起