• View载入具体解释


    文章一開始我要对前面一篇文章做点补充
    相信大家都知道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我会在下篇给大家具体解说的。
    太特么累了,我要喝脉动。

    这里写图片描写叙述

  • 相关阅读:
    智能安全实验室-全能优化(Guardio) 3.8.0.460:紧急修复功能列表点击“导出(/列表)”出现错误的问题
    Guardio全能优化3.2.0.400
    智能安全实验室-全能优化(Guardio) 3.8.0.482:修正部分错误
    智能安全实验室-Defendio杀马2.4.0.420-实时防护-内存防护、新浏览器导航界面
    智能安全实验室-杀马(Defendio) 2.3.0.409 :任务计划,用户可以定时对指定目标进行扫描、智能更新等
    微软同步框架入门之五使用WCF同步远程数据
    微软同步框架入门之四冲突(Conflict)检测和处理
    小A是支枪,子弹未打光之"步枪"篇
    微软同步框架入门之三分析生成的同步类文件
    微软同步框架入门之二增量和修改同步方式
  • 原文地址:https://www.cnblogs.com/llguanli/p/8480457.html
Copyright © 2020-2023  润新知