版权声明:本文出自汪磊的博客,转载请务必注明出处。

1 为什么要分析setContentView方法

作为安卓开发者相信大部分都有意或者无意看过如下图示:PhoneWindow,DecorView这些究竟都是些神马玩意?图示的层级关系是怎么来的?我们自己所写的布局是怎么加载到窗体上的?以及在上一篇《Android事件传递机制详解及最新源码分析——Activity篇》中提到过我们在调用setContentView设置布局的时候其实都是被放置在id为content的FrameLayout 布局中的,这里又是什么鬼?带着这些问题我们一起探讨下setContentView方法究竟做了些什么。

2 分析setContentView方法(API23)

我们平时调用setContentView,例如:setContentView(R.layout.xxx);点进源码都是先调用Activity中的setContentView方法,我们就从Activity中的setContentView方法开始分析。

Activity的源码中有三个重载的setContentView方法,如下:

1 public void setContentView(@LayoutRes intlayoutResID) {2 getWindow().setContentView(layoutResID);3 initWindowDecorActionBar();4 }5
6 public voidsetContentView(View view) {7 getWindow().setContentView(view);8 initWindowDecorActionBar();9 }10
11 public voidsetContentView(View view, ViewGroup.LayoutParams params) {12 getWindow().setContentView(view, params);13 initWindowDecorActionBar();14     } 

可以看到三个方法都是又调用了getWindow().setContentView(...);在上一篇文章中分析过getWindow()返回mWindow对象,mWindow定义是Windo类型,实际初始化的时候初始化为PhoneWindow,源码如下:

privateWindow mWindow;mWindow= new PhoneWindow(this);

这里说明一下:Window 是抽象类,主要提供一些绘制窗口的一些公用方法,PhoneWindow是Window的具体继承实现类。

我们看看Window类中setContentView方法,源码如下:

public abstract void setContentView(@LayoutRes intlayoutResID);public abstract voidsetContentView(View view);public abstract void setContentView(View view, ViewGroup.LayoutParams params);

看到了吧,这里只是三个抽象方法而已,具体逻辑需要子类自己去实现。

接下来,我们就就去PhoneWindow中找一下吧,源码如下:

@Overridepublic void setContentView(intlayoutResID) {//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();}}@Overridepublic voidsetContentView(View view) {setContentView(view,newViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}@Overridepublic voidsetContentView(View view, ViewGroup.LayoutParams params) {//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)) {view.setLayoutParams(params);final Scene newScene = newScene(mContentParent, view);transitionTo(newScene);}else{mContentParent.addView(view, params);}mContentParent.requestApplyInsets();final Callback cb =getCallback();if (cb != null && !isDestroyed()) {cb.onContentChanged();}}

看到了吧,在子类PhoneWindow中有具体实现,并且setContentView(View view)实际上也是调用的setContentView(View view, ViewGroup.LayoutParams params),只不过params参数默认传入为MATCH_PARENT。并且setContentView(int layoutResID)与setContentView(View view, ViewGroup.LayoutParams params)方法代码逻辑是一样的,这里我们选取setContentView(int layoutResID)方法加以分析即可。

到这里我们明白平时调用的setContentView(R.layout.xxx)方法实际上调用的是PhoneWindow中的setContentView(int layoutResID)方法,接下来我们着重分析此方法。

3 分析PhoneWindow中的setContentView(int layoutResID)方法(API23)

源码如下:

1 @Override2     public void setContentView(intlayoutResID) {3         //Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window4         //decor, when theme attributes and the like are crystalized. Do not check the feature5         //before this happens.
6         if (mContentParent == null) {7 installDecor();8         } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {9 mContentParent.removeAllViews();10 }11
12         if(hasFeature(FEATURE_CONTENT_TRANSITIONS)) {13             final Scene newScene =Scene.getSceneForLayout(mContentParent, layoutResID,14 getContext());15 transitionTo(newScene);16         } else{17 mLayoutInflater.inflate(layoutResID, mContentParent);18 }19 mContentParent.requestApplyInsets();20         final Callback cb =getCallback();21         if (cb != null && !isDestroyed()) {22 cb.onContentChanged();23 }24     }

第6行代码判断mContentParent 是否为空,mContentParentPhoneWindow中定义的一个ViewGroup类型实例。第一次运行的时候mContentParent 为null,则进入判断执行第7行代码

installDecor(),我们看看installDecor()方法都做了什么源码如下:这里只列出主要代码

1 private voidinstallDecor() {2         if (mDecor == null) {3             mDecor =generateDecor();4 ...5 }6         if (mContentParent == null) {7             mContentParent =generateLayout(mDecor);8 ...9 }10 ....11 } 

第2行代码判断mDecor是否为null,为null则执行generateDecor()代码并对mDecor赋值,mDecor是DecorView的一个实例,DecorView是PhoneWindow的内部类,定义如下:

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker

看到了吧,DecorView其实就是FrameLayout 的子类,对FrameLayout 进行装饰,增强其某些功能。

我们继续看generateDecor()源码:

1    protectedDecorView generateDecor() {2         return new DecorView(getContext(), -1);3     }

很简单吧就是生成DecorView对象并且返回,这里没什么要多说的。

返回installDecor()方法我们继续向下分析。

第6行代码又是判断mContentParent 是否为null,是则执行generateLayout(mDecor)方法并将返回值赋值给mContentParent

那我们就继续看generateLayout(mDecor)源码:

1 protectedViewGroup generateLayout(DecorView decor) {2         //Apply data from current theme.
3
4         TypedArray a =getWindowStyle();5
6         if (false) {7             System.out.println("From style:");8             String s = "Attrs:";9             for (int i = 0; i < R.styleable.Window.length; i++) {10                 s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
11                         +a.getString(i);12 }13 System.out.println(s);14 }15
16         mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);17         int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)18                 & (~getForcedWindowFlags());19         if(mIsFloating) {20 setLayout(WRAP_CONTENT, WRAP_CONTENT);21             setFlags(0, flagsToUpdate);22         } else{23             setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);24 }25
26         if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {27 requestFeature(FEATURE_NO_TITLE);28         } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {29             //Don't allow an action bar if there is no title.
30 requestFeature(FEATURE_ACTION_BAR);31 }32
33         if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {34 requestFeature(FEATURE_ACTION_BAR_OVERLAY);35 }36
37         if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {38 requestFeature(FEATURE_ACTION_MODE_OVERLAY);39 }40
41         if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {42 requestFeature(FEATURE_SWIPE_TO_DISMISS);43 }44
45         if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {46             setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));47 }48
49         if(a.getBoolean(R.styleable.Window_windowTranslucentStatus,50                 false)) {51 setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS52                     & (~getForcedWindowFlags()));53 }54
55         if(a.getBoolean(R.styleable.Window_windowTranslucentNavigation,56                 false)) {57 setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION58                     & (~getForcedWindowFlags()));59 }60
61         if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {62             setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));63 }64
65         if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {66             setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));67 }68
69         if(a.getBoolean(R.styleable.Window_windowEnableSplitTouch,70 getContext().getApplicationInfo().targetSdkVersion71                         >=android.os.Build.VERSION_CODES.HONEYCOMB)) {72             setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));73 }74
75 a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);76 a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);77         if(a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {78             if (mFixedWidthMajor == null) mFixedWidthMajor = newTypedValue();79 a.getValue(R.styleable.Window_windowFixedWidthMajor,80 mFixedWidthMajor);81 }82         if(a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {83             if (mFixedWidthMinor == null) mFixedWidthMinor = newTypedValue();84 a.getValue(R.styleable.Window_windowFixedWidthMinor,85 mFixedWidthMinor);86 }87         if(a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {88             if (mFixedHeightMajor == null) mFixedHeightMajor = newTypedValue();89 a.getValue(R.styleable.Window_windowFixedHeightMajor,90 mFixedHeightMajor);91 }92         if(a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {93             if (mFixedHeightMinor == null) mFixedHeightMinor = newTypedValue();94 a.getValue(R.styleable.Window_windowFixedHeightMinor,95 mFixedHeightMinor);96 }97         if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {98 requestFeature(FEATURE_CONTENT_TRANSITIONS);99 }100         if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {101 requestFeature(FEATURE_ACTIVITY_TRANSITIONS);102 }103
104         final Context context =getContext();105         final int targetSdk =context.getApplicationInfo().targetSdkVersion;106         final boolean targetPreHoneycomb = targetSdk <android.os.Build.VERSION_CODES.HONEYCOMB;107         final boolean targetPreIcs = targetSdk <android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;108         final boolean targetPreL = targetSdk <android.os.Build.VERSION_CODES.LOLLIPOP;109         final boolean targetHcNeedsOptions =context.getResources().getBoolean(110 R.bool.target_honeycomb_needs_options_menu);111         final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) ||hasFeature(FEATURE_NO_TITLE);112
113         if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions &&noActionBar)) {114 setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);115         } else{116 setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);117 }118
119         //Non-floating windows on high end devices must put up decor beneath the system bars and120         //therefore must know about visibility changes of those.
121         if (!mIsFloating &&ActivityManager.isHighEndGfx()) {122             if (!targetPreL &&a.getBoolean(123 R.styleable.Window_windowDrawsSystemBarBackgrounds,124                     false)) {125 setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,126                         FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());127 }128 }129         if (!mForcedStatusBarColor) {130             mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);131 }132         if (!mForcedNavigationBarColor) {133             mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);134 }135         if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {136 decor.setSystemUiVisibility(137                     decor.getSystemUiVisibility() |View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);138 }139
140         if (mAlwaysReadCloseOnTouchAttr ||getContext().getApplicationInfo().targetSdkVersion141                 >=android.os.Build.VERSION_CODES.HONEYCOMB) {142             if(a.getBoolean(143 R.styleable.Window_windowCloseOnTouchOutside,144                     false)) {145                 setCloseOnTouchOutsideIfNotSet(true);146 }147 }148
149         WindowManager.LayoutParams params =getAttributes();150
151         if (!hasSoftInputMode()) {152             params.softInputMode =a.getInt(153 R.styleable.Window_windowSoftInputMode,154 params.softInputMode);155 }156
157         if(a.getBoolean(R.styleable.Window_backgroundDimEnabled,158 mIsFloating)) {159             /*All dialogs should have the window dimmed*/
160             if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {161                 params.flags |=WindowManager.LayoutParams.FLAG_DIM_BEHIND;162 }163             if (!haveDimAmount()) {164                 params.dimAmount =a.getFloat(165                         android.R.styleable.Window_backgroundDimAmount, 0.5f);166 }167 }168
169         if (params.windowAnimations == 0) {170             params.windowAnimations =a.getResourceId(171                     R.styleable.Window_windowAnimationStyle, 0);172 }173
174         //The rest are only done if this window is not embedded; otherwise,175         //the values are inherited from our container.
176         if (getContainer() == null) {177             if (mBackgroundDrawable == null) {178                 if (mBackgroundResource == 0) {179                     mBackgroundResource =a.getResourceId(180                             R.styleable.Window_windowBackground, 0);181 }182                 if (mFrameResource == 0) {183                     mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);184 }185                 mBackgroundFallbackResource =a.getResourceId(186                         R.styleable.Window_windowBackgroundFallback, 0);187                 if (false) {188                     System.out.println("Background: "
189                             + Integer.toHexString(mBackgroundResource) + " Frame: "
190                             +Integer.toHexString(mFrameResource));191 }192 }193             mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);194             mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);195             mTextColor =a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);196 }197
198         //Inflate the window decor.
199
200         intlayoutResource;201         int features =getLocalFeatures();202         //System.out.println("Features: 0x" + Integer.toHexString(features));
203         if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {204             layoutResource =R.layout.screen_swipe_dismiss;205         } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {206             if(mIsFloating) {207                 TypedValue res = newTypedValue();208 getContext().getTheme().resolveAttribute(209                         R.attr.dialogTitleIconsDecorLayout, res, true);210                 layoutResource =res.resourceId;211             } else{212                 layoutResource =R.layout.screen_title_icons;213 }214             //XXX Remove this once action bar supports these features.
215 removeFeature(FEATURE_ACTION_BAR);216             //System.out.println("Title Icons!");
217         } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
218                 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {219             //Special case for a window with only a progress bar (and title).220             //XXX Need to have a no-title version of embedded windows.
221             layoutResource =R.layout.screen_progress;222             //System.out.println("Progress!");
223         } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {224             //Special case for a window with a custom title.225             //If the window is floating, we need a dialog layout
226             if(mIsFloating) {227                 TypedValue res = newTypedValue();228 getContext().getTheme().resolveAttribute(229                         R.attr.dialogCustomTitleDecorLayout, res, true);230                 layoutResource =res.resourceId;231             } else{232                 layoutResource =R.layout.screen_custom_title;233 }234             //XXX Remove this once action bar supports these features.
235 removeFeature(FEATURE_ACTION_BAR);236         } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {237             //If no other features and not embedded, only need a title.238             //If the window is floating, we need a dialog layout
239             if(mIsFloating) {240                 TypedValue res = newTypedValue();241 getContext().getTheme().resolveAttribute(242                         R.attr.dialogTitleDecorLayout, res, true);243                 layoutResource =res.resourceId;244             } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {245                 layoutResource =a.getResourceId(246 R.styleable.Window_windowActionBarFullscreenDecorLayout,247 R.layout.screen_action_bar);248             } else{249                 layoutResource =R.layout.screen_title;250 }251             //System.out.println("Title!");
252         } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {253             layoutResource =R.layout.screen_simple_overlay_action_mode;254         } else{255             //Embedded, so no decoration is needed.
256             layoutResource =R.layout.screen_simple;257             //System.out.println("Simple!");
258 }259
260 mDecor.startChanging();261
262         View in = mLayoutInflater.inflate(layoutResource, null);263         decor.addView(in, newViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));264         mContentRoot =(ViewGroup) in;265
266         ViewGroup contentParent =(ViewGroup)findViewById(ID_ANDROID_CONTENT);267         if (contentParent == null) {268             throw new RuntimeException("Window couldn't find content container view");269 }270
271         if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {272             ProgressBar progress = getCircularProgressBar(false);273             if (progress != null) {274                 progress.setIndeterminate(true);275 }276 }277
278         if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {279 registerSwipeCallbacks();280 }281
282         //Remaining setup -- of background and title -- that only applies283         //to top-level windows.
284         if (getContainer() == null) {285             finalDrawable background;286             if (mBackgroundResource != 0) {287                 background =getContext().getDrawable(mBackgroundResource);288             } else{289                 background =mBackgroundDrawable;290 }291 mDecor.setWindowBackground(background);292
293             finalDrawable frame;294             if (mFrameResource != 0) {295                 frame =getContext().getDrawable(mFrameResource);296             } else{297                 frame = null;298 }299 mDecor.setWindowFrame(frame);300
301 mDecor.setElevation(mElevation);302 mDecor.setClipToOutline(mClipToOutline);303
304             if (mTitle != null) {305 setTitle(mTitle);306 }307
308             if (mTitleColor == 0) {309                 mTitleColor =mTextColor;310 }311 setTitleColor(mTitleColor);312 }313
314 mDecor.finishChanging();315
316         returncontentParent;317     }

我勒个去,这方法太挺长,不过别担心,总体逻辑不复杂。

第4行代码getWindowStyle()是什么鬼呢?这里就直接说了,我们在manifest文件配置的Activity的时候有时会指定theme,如:android:theme="@style/AppTheme",getWindowStyle()就是获取我们配置的theme信息。

接着6-199行代码都是根据我们通过getWindowStyle()获取的theme配置信息进行相应设置。

200行代码,定义layoutResource变量。

201调用getLocalFeatures()方法又是干什么呢?我们有时会通过代码对Activity设置一些Feature,如:requestWindowFeature(Window.FEATURE_NO_TITLE);这里getLocalFeatures()方法就是获取通过requestWindowFeature设置的一些值。

202-258根据获取的features不同对layoutResource进行不同的赋值,layoutResource主要纪录不同的布局文件。如果什么也没设置,也就是说Activity没有任何修饰,那么就赋值为

R.layout.screen_simple,我们看一下R.layout.screen_simple布局源码:

1 <?xml version="1.0" encoding="utf-8"?>
2
3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
4     android:layout_width="match_parent"
5     android:layout_height="match_parent"
6     android:fitsSystemWindows="true"
7     android:orientation="vertical">
8     <ViewStub android:id="@+id/action_mode_bar_stub"
9               android:inflatedId="@+id/action_mode_bar"
10               android:layout="@layout/action_mode_bar"
11               android:layout_width="match_parent"
12               android:layout_height="wrap_content"
13               android:theme="?attr/actionBarTheme" />
14     <FrameLayout15          android:id="@android:id/content"
16          android:layout_width="match_parent"
17          android:layout_height="match_parent"
18          android:foregroundInsidePadding="false"
19          android:foregroundGravity="fill_horizontal|top"
20          android:foreground="?android:attr/windowContentOverlay" />
21 </LinearLayout>

看到了吧,很简单,就包括一个actiob_Bar,还有一个id为content的FrameLayout,并且action_Bar部分使用了布局优化ViewStub 。

继续向下分析262行将layoutResource记录的布局转化为View。

263行代码将262行生成的view添加到decor中,这个decor就是我们上面分析过的mDecor。

264行将262行生成的View赋值给mContentRoot,用以纪录。

接下来266行通过findViewById找到ID为ID_ANDROID_CONTENT的View,这个ID_ANDROID_CONTENT又是什么鬼?通过查找最终在父类Window中找到,源码如下:

public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

看到了吧,就是id为content的View,以R.layout.screen_simple布局为例,最终找的就是id为content的FrameLayout。赋值给名为contentParent的ViewGroup。

最终在316行将contentParent作为generateLayout方法的返回值返回。到此generateLayout想要探讨的就都探讨完了。

我们马上回看上面分析的installDecor()方法第7行。将generateLayout方法返回值赋值给mContentParent,到这里,你应该知道mContentParent就是DecorView中布局为content的部分。

我们在回看一开始分析的setContentView方法,之前分析到第7行,继续向下看直到第17行,调用mLayoutInflater.inflate(layoutResID, mContentParent),至于inflate方法内部逻辑这里就不分析了,不是本文重点,直接说结论:mLayoutInflater.inflate(layoutResID, mContentParent)就是将layoutResID布局转化为View添加到mContentParent中。还记得mContentParent吗?它就是DecorView中id为content的View。到这里就知道了原来我们自己定义的布局最终都是加载到这里了。

4总结

经过上面分析相信你已经有了一些眉目,我们赶紧总结一下。

我们平时在Activity中调用的setContentView方法其实都是调用的PhoneWindow中的setContentView方法,其首先会判断mContentParent是否为null,如果为null,则执行installDecor()方法,在installDecor()方法中会对mDecor进行判断是否为null,为null则进行初始化,mDecor为DecorView类型,DecorView继承自FrameLayout。接下来继续判断mContentParent是否为null,为null则执行generateLayout方法,在generateLayout方法中最重要的逻辑就是根据我们设置的不同feature找到对应布局文件,并且inflate为View,通过addView方法加入到mDecor中,然后找到布局文件中ID为content的View作为generateLayout方法最终返回值返回。接下来回到installDecor方法将generateLayout返回值赋值给mContentParent,最后回到setContentView,将我们自己的布局文件layoutResID加载到mContentParent中。

相信经过上述分析你应该对本文一开始的那张图会有更深刻的认识。

转载于:https://www.cnblogs.com/leipDao/p/7509222.html

Android之View绘制流程开胃菜---setContentView(...)详细分析相关推荐

  1. Android中View绘制流程以及invalidate()等相关方法分析

                                                                                                        ...

  2. android字符显示流程图,Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  3. Android应用层View绘制流程与源码分析

    前言 Activity中界面加载显示的基本流程原理,最终分析结果就是下面的关系: 看见没有,如上图中id为content的内容就是整个View树的结构,所以对每个具体View对象的操作,其实就是个递归 ...

  4. Android自定义View绘制流程

    Android视图层次结构简介 在介绍View绘制流程之前,咱们先简单介绍一下Android视图层次结构以及DecorView,因为View的绘制流程的入口和DecorView有着密切的联系. 我们平 ...

  5. Android中View绘制流程

    2019独角兽企业重金招聘Python工程师标准>>> 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程 ...

  6. Android中View绘制流程分析

    创建Window 在Activity的attach方法中通过调用PolicyManager.makeNewWindo创建Window,将一个View add到WindowManager时,Window ...

  7. Android面试,View绘制流程以及invalidate()等相关方法分析

    整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measu ...

  8. Android之View绘制流程源码分析

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 对于稍有自定义View经验的安卓开发者来说,onMeasure,onLayout,onDraw这三个方法都不会陌生,起码多少都有所接触吧. 在安卓中 ...

  9. Android中View绘制各种状态的背景图片原理深入分析以及StateListDrawable使用

    /* Call this to force a view to update its drawable state. This will cause drawableStateChanged to b ...

最新文章

  1. MySQL基础(二):视图、触发器、函数、事务、存储过程
  2. 2.3、Android Studio使用Layout Editor设计UI
  3. JZ32变形~剑指 Offer 32 - II. 从上到下打印二叉树 II
  4. Python数据科学学习进阶
  5. Xcode编译后运行程序Killed: -9,因为签名有问题
  6. 六石管理学:你觉得别人错了,应该怎么办
  7. 从省市级到区县级,Power BI topoJSON 中国行政区划地图都在这了
  8. 解决Vue 2.0在IE11版本浏览器中的兼容性问题
  9. python逆序输出字符串_Python实现字符串逆序输出功能示例
  10. 十进制转化为十二进制
  11. (超详细)张正友标定法原理及公式推导
  12. 常用的mysql sql语句_常用的SQL语句(MySQL)
  13. 敌兵布阵(CDQ分治模板题)
  14. python @property 解释
  15. php strpos 区分大小写么?,PHP strpos() 函数
  16. 个人的工作总结(和工作规划)
  17. 无心剑汉英双语诗005.《抒怀》
  18. win10管理员无法使用mklink的问题
  19. Linux Centos7 安装Tomcat9并配置环境变量
  20. 动态下载苹果提供的多种中文字体

热门文章

  1. 程序员的数学笔记1--进制转换
  2. 手游服务器验证,手游登录流程
  3. 【NOIP 2017】列队
  4. Microsoft SQL Server 全角转半角函数
  5. Java内存模型_基础
  6. JZOJ 8.15 B组总结
  7. solr 配置中文分词器
  8. 赵雅智:service_startService生命周期
  9. 永远要跟比你更成功的人在一起
  10. java 创建线程的三种方法_java 创建线程的几种方式