文章一開始我要对前面一篇文章做点补充

相信大家都知道View有两个方法。

 public boolean post(Runnable action)
public boolean postDelayed(Runnable action, long delayMillis) {

这两个方法也能够实现对View的包装(实现延时发送消息和更新UI)那么它和Handler有什么差别呢下面给出源代码。

/**
* <p>Causes the Runnable to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the user interface thread.</p>
*<BR>使Runnable被加入到消息队列。执行将执行在用户界面线程。@param行动的执行将被执行。 * @返回返回true假设执行成功放置到
*消息队列。 执行失败将返回False。一般是由于
* looper处理消息队列退出。
* @param action The Runnable that will be executed.
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* @return true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* @see #post
* @see #removeCallbacks
*/
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}
/**
* <p>Causes the Runnable to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the user interface thread.</p>
*使Runnable被加入到消息队列,能够执行在指定时间的流逝之后
* @param action The Runnable that will be executed.
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* @return true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* @see #post
* @see #removeCallbacks
*/
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}

关键的凝视我也进行的翻译。相信大家如今已经明确了。

在post(Runnable action)方法里。View获得当前线程(即UI线程)的Handler。然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此。我们能够毫无顾虑的来更新UI。

这样的情况下。由于不是在新的线程中使用,所以千万别做复杂的计算逻辑。更不能进行耗时操作了

那大家又会问什么是ViewRootImpl?这特么又是什么鬼,这里给大家解说一下。我们从最基础的讲起。

相信大家都知道我们通过调用setContentView(int layoutResID)把xml文件载入到当前Activity上的。

那我们就从setContentView讲起。

public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}

setContentView方法实现非常easy,里面调用两个方法,我们这里分析第一个方法:

getWindow()得到一个Window对象 mWindow ,Window是一个抽象类,用来描写叙述Activity视图最顶端的窗体显示和行为操作。Window是一个抽象类。那么里面的setContentView(layoutResID)是一个抽象方法。并没有具体的实现。既然Window是一个抽象类,那么在Activity里面就有一个Window抽象类的实现。们查找代码发现 mWindow对象赋值方法例如以下。

mWindow = PolicyManager.makeNewWindow(this);

继续看看 PolicyManager类

public final class More PolicyManager {
30 private static final String POLICY_IMPL_CLASS_NAME =
31 "com.android.internal.policy.impl.Policy";
32
33 private static final IPolicy sPolicy;
34
35 static {
36 // Pull in the actual implementation of the policy at run-time
37 try {
38 Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
39 sPolicy = (IPolicy)policyClass.newInstance();
40 } catch (ClassNotFoundException ex) {
41 throw new RuntimeException(
42 POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
43 } catch (InstantiationException ex) {
44 throw new RuntimeException(
45 POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
46 } catch (IllegalAccessException ex) {
47 throw new RuntimeException(
48 POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
49 }
50 }
51
52 // Cannot instantiate this class
53 private More PolicyManager() {}
54
55 // The static methods to spawn new policy-specific objects
56 public static Window More makeNewWindow(Context context) {
57 return sPolicy.makeNewWindow(context);
58 }

通过分析我们发现sPolicy对象是有第 38。39行通过径”com.android.internal.policy.impl.Policy“生成的(通过反射拿到类的对象而且实例化)重点57,

public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}

由此可见,我们最终找到Activity类中的 mWindow对象的实现类了。就是PhoneWindow类。

可能又会有些童学问什么是反射呢?what Fuck,要是特么这样扯下去,预计三天三夜也扯不完,等这篇写完后,会专一分一篇来解说Java的反射机制。

到PhoneWindow类发现了setContentView方法的实现也在这个类里面了

@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);
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}

首先推断mContentParent是否为null,mContentParent是什么呢?接下来会分析,一開始条件成立,进入installDecor()方法

到installDecor()方法里,实现例如以下:

 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(); 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)) {
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);
}
}
}
}

重点在代码的第 3 行我们看到 mDecor = generateDecor();方法调用,继续跳进 generateDecor()方法:

protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}

这里生成一个DecorView对象,DecorView是PhoneWindow类的内部类,继承自FrameLayout。到眼下为止。setContentView方法里生成一个FrameLayout类型的DecorView组件。

继续分析代码,看第 11 行:

mContentParent = generateLayout(mDecor);
把 DecorView 对象 mDecor 作为參数传递给 generateLayout方法得到 mContentParent。

generateLayout()方法中的代码实现例如以下:
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme. TypedArray a = getWindowStyle(); ......... /**下面这些是Activity 窗体属性特征的设置*/
//窗体是否浮动,一般用于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 (!mForcedStatusBarColor) {
mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
}
//设置导航栏的颜色
if (!mForcedNavigationBarColor) {
mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
} 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);
} //下面代码为当前Activity窗体加入 decor根布局。
// Inflate the window decor. 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(); //通过布局加入器LayoutInflater获取layoutResource布局,
View in = mLayoutInflater.inflate(layoutResource, null);
//将XML资源为layoutResource的布局加入到decor容器里面。至此PhoneWindow 内部类DecorView就加入了之布局
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in; //此处非常重要。通过findViewById找到 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();
} // Remaining setup -- of background and title -- that only applies
// to top-level windows.
//下面代码设置Activity窗体的背景,标题等
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;
}

以上代码代比較复杂。主要做了下面几件事情。

从第 8 行到第110行,主要是初始化窗体的特征。是否显示标题栏。是否全屏,是否支持ActionBar浮动等等。

第112-187行。主要是给容器DecorView加入id为layoutResource布局的根布局。待会分析layoutResource布局。

第178行。通过LayoutInflater 将xml布局转换成VIEW.

第180行将找到的View加入到DecorView根布局其中。

第184行,从根布局中找到id为R.id.content的 contentParent 容器。也就是当前方法的返回值。

接下来,看看 id为layoutResource的布局究竟实现了什么?我们来看看171行的R.layout.screen_simple;资源

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="? android:attr/windowContentOverlay" />
</LinearLayout>

原来我们的DecorView根布局里面加入了相似上面的布局,线性布局LinearLaout里包括两个组件,ViewStub是懒载入,默认不显示。FrameLayout是什么呢?看看id=content,就是我们184行找到的父容器 contentParent。那么这个父容器 contentParent有什么作用呢?

我们回到 Step4 的第 11行,mContentParent = generateLayout(mDecor); 获得 父容器 mContentParent。我们再次回到 Step3步的第17行, mLayoutInflater.inflate(layoutResID, mContentParent); 这里通过LayoutInflater将 setContentView(layoutResID)传进来的布局id载入到 父容器mContentParent中,至此。setContentView就将布局加入到Activity里面了。

如今我们来梳理一下流程:

Activity setContentView—>Window setContentView—>PhoneWindow setContentView—->PhoneWindow installDecor—–>PhoneWindow generateLayout——>PhoneWindow mLayoutInflater.inflate(layoutResID, mContentParent);

Activity 类中有一个Window抽象类的实现PhoneWindow类,该类中有个内部类DecorView。继承自FrameLayout。在DecorView容器中加入了根布局。根布局中包括了一个id为 contnet的FrameLayout 内容布局。我们的Activity载入的布局xml最后加入到 id为content的FrameLayout布局其中了

1.关于requestWindowFeature(Window.FEATURE_NO_TITLE); 去除标题栏的疑问,假设你自己的xxxActivity是继承自Activity。那么恭喜你使用以上方法能够去除标题栏,假设你自己的xxxActivity是继承自AppCompatActivity或者ActionBarActivity,那么非常遗憾告诉你,此次系统默认的标题栏已经在主题中去除,此时显示的标题栏是ActionBar导航栏,假设须要去除导航栏,你能够通过例如以下代码:getSupportActionBar().hide();来隐藏导航栏。

2.requestWindowFeature(Window.FEATURE_NO_TITLE);方法须要在 setContentView方法之前使用。由上面 Step5分析可得。设置Activity Window 特征是在setContentView方法中设置的,因此,假设须要改变Activity Window窗体特征,须要在setContentView方法之前。

事实上这里有疑问???为什么设置全屏的方法getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

关于mLayoutInflater.inflate我会在下篇给大家具体解说的。

太特么累了,我要喝脉动。

View载入具体解释的更多相关文章

  1. Android物业动画研究(Property Animation)彻底解决具体解释

     前p=1959">Android物业动画研究(Property Animation)全然解析具体解释上已经基本展示了属性动画的核心使用方法: ObjectAnimator实现动画 ...

  2. TransactionScope事务处理方法介绍及.NET Core中的注意事项 SQL Server数据库漏洞评估了解一下 预热ASP.NET MVC 的VIEW [AUTOMAPPER]反射自动注册AUTOMAPPER PROFILE

    TransactionScope事务处理方法介绍及.NET Core中的注意事项   作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.ht ...

  3. Universal-Image-Loader(UIL)图片载入框架使用简介

    这个也是近期项目中使用到的第三方图片载入框架.在这里也自己总结一下,简单的介绍一些使用的方式. UIL图片载入框架特点 简单介绍: 项目地址:https://github.com/nostra13/A ...

  4. android 中View的优化

    在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候, ...

  5. 【转】通知 Toast详细用法(显示view)

    原文网址:http://www.pocketdigi.com/20100904/87.html 今天学习Android通知 Toast的用法,Toast在手机屏幕上向用户显示一条信息,一段时间后信息会 ...

  6. iOS UIWebView 载入https 网站出现NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL,

    今天在载入https网站的时候遇到例如以下的错误问题.所以对自己之前写的iOS内嵌webview做了一些改动,能够让它载入http网站也能够让它载入https网站. 以下是我载入https网站的时候出 ...

  7. 预热ASP.NET MVC 的View

    ASP.NET MVC 的View 预设是Load on Demand(按需加载),也就是说View 第一次要Render 的时候才会去载入跟编译,这个就会造成一个现象,即使Web 应用程式已经完成启 ...

  8. 【MVC】View的使用

    /Views/_ViewStart.cshtml 文件会在其他视图文档被加载之前被载入,代码如下: @{ Layout = "~/Views/Shared/_Layout.cshtml&qu ...

  9. 从LayoutInflater分析XML布局解析成View的树形结构的过程

    上一篇博客分析了XML布局怎么载入到Activity上.不了解的能够參考 从setContentView方法分析Android载入布局流程 上一篇博客仅仅是分析了怎么讲XML布局加入到 Activit ...

随机推荐

  1. 61配置nanopim1plus的HDMI为1080p输出

    61配置nanopim1plus的HDMI为1080p输出 大文实验室/大文哥 壹捌陆捌零陆捌捌陆捌贰 21504965 AT qq.com 完成时间:2018/4/4 10:21 版本:V1.1 开 ...

  2. 字符编码方式ASCII、Unicode、UTF-8

    一.ASCII 1.介绍 即American Standard Code for Information Interchange(美国信息交换标准代码),是基于拉丁字母的,主要用于显示现代英语和其他西 ...

  3. day21-2 类的派生

    目录 类的派生 派生方法一 派生方法二 类的派生 派生:子类中新定义属性的这个过程叫做派生 派生方法一 指明道姓访问某一个类的函数:该方法与继承无关 class People: def __init_ ...

  4. CSS绝对定位模拟固定定位

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. vue之基础---组件基础

    (1)基本示例 Vue组件示例 /* 先注册组件,定义一个名为button-component的新组件 */ Vue.component('button-component',{ data:funct ...

  6. 华登区块狗系统APP开发

    华登区块狗系统开发,陈翎:{.l8O..285l..l22O.}华登区块狗软件开发,华登区块狗APP开发,华登区块狗模式开发,华登区块狗现成源码,狗狗集市理财模式开发 华登区块狗是什么?华登区块狗ap ...

  7. svn更新报错Please execute the 'Cleanup' command.

    更新svn报错 要Clearnup一下就可以再更新了 点击svn中 clear up ok之后恢复正常

  8. JQurey---新尝试

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  9. AD7606

    在只给芯片的RANGE和PAR_SER引脚上电(不给芯片加电)的时候,芯片严重发热. 改回给芯片加电,发热消失,芯片正常工作,芯片没有损坏. 版权声明:本文为博主原创文章,未经博主允许不得转载.

  10. RequestMapping_PathVariable注解

    [@PathVariable 映射URL绑定的占位符] 1.带占位符的URL是Spring 3.0 新增的功能,该功能在Spring MVC向 REST 目标挺进发展过程中具有里程碑的意义. 2.通过 ...