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

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

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 int layoutResID) {
 2         getWindow().setContentView(layoutResID);
 3         initWindowDecorActionBar();
 4     }   
 5 
 6 public void setContentView(View view) {
 7         getWindow().setContentView(view);
 8         initWindowDecorActionBar();
 9     }
10 
11 public void setContentView(View view, ViewGroup.LayoutParams params) {
12         getWindow().setContentView(view, params);
13         initWindowDecorActionBar();
14     } 

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

private Window mWindow;mWindow = new PhoneWindow(this);

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

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

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

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

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

    @Overridepublic 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();}}@Overridepublic void setContentView(View view) {setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}@Overridepublic void setContentView(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 = new Scene(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  @Override
 2     public void setContentView(int layoutResID) {
 3         // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
 4         // decor, when theme attributes and the like are crystalized. Do not check the feature
 5         // 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 是否为空,mContentParent PhoneWindow中定义的一个ViewGroup类型实例。第一次运行的时候mContentParent 为null,则进入判断执行第7行代码

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

 1 private void installDecor() {
 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    protected DecorView generateDecor() {
2         return new DecorView(getContext(), -1);
3     }

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

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

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

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

  1 protected ViewGroup 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_STATUS
 52                     & (~getForcedWindowFlags()));
 53         }
 54 
 55         if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
 56                 false)) {
 57             setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
 58                     & (~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().targetSdkVersion
 71                         >= 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 = new TypedValue();
 79             a.getValue(R.styleable.Window_windowFixedWidthMajor,
 80                     mFixedWidthMajor);
 81         }
 82         if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
 83             if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
 84             a.getValue(R.styleable.Window_windowFixedWidthMinor,
 85                     mFixedWidthMinor);
 86         }
 87         if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
 88             if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
 89             a.getValue(R.styleable.Window_windowFixedHeightMajor,
 90                     mFixedHeightMajor);
 91         }
 92         if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
 93             if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
 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 and
120         // 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().targetSdkVersion
141                 >= 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         int layoutResource;
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 = new TypedValue();
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 = new TypedValue();
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 = new TypedValue();
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, new ViewGroup.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 applies
283         // to top-level windows.
284         if (getContainer() == null) {
285             final Drawable background;
286             if (mBackgroundResource != 0) {
287                 background = getContext().getDrawable(mBackgroundResource);
288             } else {
289                 background = mBackgroundDrawable;
290             }
291             mDecor.setWindowBackground(background);
292 
293             final Drawable 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         return contentParent;
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     <FrameLayout
15          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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/428741.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

排序算法之堆排序

一、什么是堆 如果一个完全二叉树的每个节点&#xff0c;都不大于它的子节点&#xff0c;就可以称之为堆。所谓完全二叉树&#xff0c;就是除了叶子节点以外&#xff0c;所有的其他节点&#xff0c;都有完整的左字树和右子树&#xff0c;除了最后一层的非叶子节点以外。 二、堆…

Codeforces Round #434 (Div. 2)【A、B、C、D】

Codeforces Round #434 (Div. 2) codeforces 858A. k-rounding【水】 题意&#xff1a;已知n和k&#xff0c;求n的最小倍数x&#xff0c;要求x后缀至少有k个0。 题解&#xff1a;答案就是10^k和n的最小公倍数。 1 #include<cstdio>2 #include<cstring>3 #include&l…

PLC与触摸屏练习

电机正反转 触摸屏 要用触摸屏进行仿真是不要忘了先启动梯形图测试 效果 1-2例 行程开关控制的自动循环 梯形图 触摸屏 下面只是用了四个开关&#xff0c;可以根据自己想要实现的按照梯形图添加 题目 梯形图 电动机星三角减压启动控制 题目及要求 触摸屏截图 运算 把显示的数值…

Django里面是文件静态化的方法

看Django官网的时候&#xff0c;由于自己的英语基础较差&#xff0c;而实现的谷歌翻译比较烂&#xff0c;只能看懂个大概。在文件静态化的时候&#xff0c;讲的比较繁琐一点&#xff0c;没怎么看懂&#xff0c;遂询问了一下其他人&#xff0c;明白了许多&#xff0c;但是细节需…

RabbitMQ 声明Queue时的参数们的Power

RabbitMQ 声明Queue时的参数们的Power 参数们的Power 在声明队列的时候会有很多的参数 public static QueueDeclareOk QueueDeclare(this IModel model, string queue "", bool durable false, bool exclusive true, bool autoDelete true, IDictionary<strin…

解决Firefox已阻止运行早期版本Adobe Flash

解决Firefox已阻止运行早期版本Adobe Flash 类别 [随笔分类]web 解决Firefox已阻止运行早期版本Adobe Flash 最近火狐浏览器不知抽什么风&#xff0c;每次打开总提示"Firefox已阻止(null)运行早期版本的Adobe Flash"。要命的是它提示的解决办法根本不管用&#xf…

使用MyBatista----上传图像

使用MyBatis上传图像&#xff0c;使用的是Oracle的数据库表&#xff0c;有一个TEACHER表&#xff0c;有7列&#xff0c;有1列是存储图片的&#xff0c;类型用BLOB&#xff0c;最大容量是4G&#xff0c;以二进制的形式写入数据库表。 建立这个表的对应实体类Teacher&#xff0c;…

BZOJ 2768 [JLOI2010]冠军调查

还说还剩十分钟A一道水题&#xff0c;然后发现和善意的投票一模一样粘个代码过去直接A。。。 装作自己又写了一道题。 题面 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #include<…

【OpenCV函数】轮廓提取;轮廓绘制;轮廓面积;外接矩形

FindContours 在二值图像中寻找轮廓 int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int header_sizesizeof(CvContour), int modeCV_RETR_LIST, int methodCV_CHAIN_APPROX_SIMPLE, CvPoint offsetcvPoint(0,0) ); image 输入的 8-比…

Windows下编译TensorFlow1.3 C++ library及创建一个简单的TensorFlow C++程序

由于最近比较忙&#xff0c;一直到假期才有空&#xff0c;因此将自己学到的知识进行分享。如果有不对的地方&#xff0c;请指出&#xff0c;谢谢&#xff01;目前深度学习越来越火&#xff0c;学习、使用tensorflow的相关工作者也越来越多。最近在研究tensorflow线下采用 pytho…

粉红小猪中有一个叫“快乐小鸡”的游戏

最近在学习svg,书看了一本 然后再找了个框架 snap.svg 摸索着写了个游戏给女儿玩。哈哈。即涨知识又娱乐。 转载于:https://www.cnblogs.com/goldli/p/7649898.html

idea .defaultMessage

idea .defaultMessage 等同于eclipse里的getDefaultMessage idea只能能获取到bean设置NotBlank等message响应到jsp的key&#xff0c;不能在jsp里获取validationMessage properties文件里的value 那么我们就不要value只要key 转载于:https://www.cnblogs.com/duneF/p/7654780.h…

【vue系列之二】详解vue-cli 2.0配置文件

上次给大家分享的是用vue-cli快速搭建vue项目&#xff0c;虽然很省时间和精力&#xff0c;但想要真正搞明白&#xff0c;我们还需要对其原理一探究竟。 大家拿到一个项目&#xff0c;要快速上手&#xff0c;正确的思路是这样的&#xff1a; 首先&#xff0c;如果在项目有readme…

4. Spring 如何通过 XML 文件配置Bean,以及如何获取Bean

在 Spring 容器内拼凑 bean 叫做装配。装配 bean 的时候&#xff0c;你是在告诉容器&#xff0c;需要哪些 bean &#xff0c;以及容器如何使用依赖注入将它们配合在一起。 理论上&#xff0c;bean 装配的信息可以从任何资源获得&#xff0c;包括属性文件&#xff0c;关系数据库…

基于用户击键特征的身份鉴别系统

简单来说&#xff0c;我们要做的就是一种通过用户敲击键盘的习惯进行身份鉴别的系统。国内外之前有一些相关研究&#xff0c;但是通常是数千条数据训练&#xff0c;而且不能随意改变敲击的字符串&#xff0c;或者是有的要求采用带有压力传感器的键盘&#xff0c;难以实用和推广…

常见三种字符编码的区别:ASCII、Unicode、UTF-8

什么是字符编码&#xff1f; 计算机只能处理数字&#xff0c;如果要处理文本&#xff0c;就必须先把文本转换为数字才能处理。最早的计算机在设计时采用8个比特&#xff08;bit&#xff09;作为一个字节&#xff08;byte&#xff09;&#xff0c;所以&#xff0c;一个字节能表…

导航,头部,CSS基础

制作自己的导航条。HTML头部元素&#xff1a;<base> 定义了页面链接标签的默认链接地址<style> 定义了HTML文档的样式文件<link> 定义了一个文档和外部资源之间的关系练习样式表&#xff1a;行内样式表内嵌样式表外部样式表分别练习定义三类选择器&#x…

十五、导航,头部,CSS基础

制作自己的导航条。HTML头部元素&#xff1a;<base> 定义了页面链接标签的默认链接地址<style> 定义了HTML文档的样式文件<link> 定义了一个文档和外部资源之间的关系 练习样式表&#xff1a;行内样式表内嵌样式表外部样式表分别练习定义三类选择器&#…

【网络爬虫入门04】彻底掌握BeautifulSoup的CSS选择器

【网络爬虫入门04】彻底掌握BeautifulSoup的CSS选择器 广东职业技术学院 欧浩源 2017-10-21 1、引言 目前&#xff0c;除了官方文档之外&#xff0c;市面上及网络详细介绍BeautifulSoup使用的技术书籍和博客软文并不多&#xff0c;而在这仅有的资料中介绍CSS选择器的少之又少。…

Mybatis基于XML配置SQL映射器(一)

Durid和Mybatis开发环境搭建 SpringBoot搭建基于SpringSpringMvcMybatis的REST服务&#xff08;http://www.cnblogs.com/nbfujx/p/7694768.html&#xff09; Mybatis之代码生成器 Maven Plugin管理 1 <build>2 <plugins>3 <plugin>4 …