从setContentView()谈起

从setContentView()谈起,第1张

概述原文链接:http://www.cnblogs.com/GMCisMarkdownCraftsman/p/3754407.html从setContentView()谈起本文主要讲解View或者ViewGroup是如何添加到应用程序的窗口中的。1.最简单的Activity一个Activity最简单的结构是如下:publicclassMainActivit 原文链接:http://www.cnblogs.com/GMCisMarkdownCraftsman/p/3754407.html从setContentVIEw()谈起

本文主要讲解VIEw或者VIEwGroup是如何添加到应用程序的窗口中的。

1. 最简单的Activity

一个Activity最简单的结构是如下:

     public class MainActivity extends Activity {        private button taskSwitch;        @OverrIDe        protected voID onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            //那就从这个setContentVIEw开启我们的VIEw或者VIEwGroup加载之旅吧            setContentVIEw(R.layout.activity_main);        }    }

R.layout.activity_main.xml结构如下:

    <relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"        xmlns:tools="http://schemas.androID.com/tools"        androID:layout_wIDth="match_parent"        androID:layout_height="match_parent"        androID:paddingBottom="@dimen/activity_vertical_margin"        androID:paddingleft="@dimen/activity_horizontal_margin"        androID:paddingRight="@dimen/activity_horizontal_margin"        androID:paddingtop="@dimen/activity_vertical_margin"        tools:context=".MainActivity" >            <button androID:ID="@+ID/taskSwitch"            androID:layout_wIDth="wrap_content"            androID:layout_height="wrap_content"            androID:text="@string/taskSwitch"/>        </relativeLayout>
2. setContentVIEw关键流程顺序图

Step1 Activity.setContentVIEw()

这个方法是Activity里面的方法,直接回调了Window的getContentVIEw(),而mWindow对象实际上是PhoneWindow对象。
frameworks/base/core/java/androID/app/Activity.java

    public class Activity extends ContextthemeWrapper                                                                                   implements LayoutInflater.Factory2,                                                                                         Window.Callback, KeyEvent.Callback,                                                                                         OnCreateContextMenuListener, ComponentCallbacks2 {                    public voID setContentVIEw(int layoutResID) {              getwindow().setContentVIEw(layoutResID);          }                    public Window getwindow() {              return mWindow;   //Window对象,实际上是一个PhoneWindow对象,它是在AMS初始化的时候创建的          }    }

AMS初始化的时候会调用PolicyManager.makeNewWindow(this);

    public class Activity extends ContextthemeWrapper                                                                                   implements LayoutInflater.Factory2,                                                                                         Window.Callback, KeyEvent.Callback,                                                                                         OnCreateContextMenuListener, ComponentCallbacks2 {                    final voID attach(Context context, ActivityThread aThread,                                                                          Instrumentation instr, IBinder token, int IDent,                Application application, Intent intent, ActivityInfo info,                                                                  CharSequence Title, Activity parent, String ID,                                                                             NonConfigurationInstances lastNonConfigurationInstances,                Configuration config) {            attachBaseContext(context);                        mFragments.attachActivity(this, mContainer, null);                         mWindow = PolicyManager.makeNewWindow(this); //这里创建的实际上是PhoneWindow对象            mWindow.setCallback(this);            mWindow.getLayoutInflater().setPrivateFactory(this);                                                                        ……        }     }

而PolicyManager是调用的IPolicy的接口实现穿件Window的。

    public final class PolicyManager {         private static final String POliCY_IMPL_CLASS_name =             "com.androID.internal.policy.impl.Policy";                      private static final IPolicy sPolicy;         ……         public static Window makeNewWindow(Context context) {                                                                             return sPolicy.makeNewWindow(context);                                                                                    }         ……    }

frameworks/base/policy/src/com/androID/internal/policy/impl/Policy.java实现了IPolicy接口,创建了Window对象,实际上是PhoneWindow对象

     // Simple implementation of the policy interface that spawns the right     // set of objects     public class Policy implements IPolicy {                                                                                          private static final String TAG = "PhonePolicy";          ……         public Window makeNewWindow(Context context) {         return new PhoneWindow(context); //创建了Window对象,实际上是PhoneWindow对象         }    }

到此,我们知道Activity.setContentVIEw()最终调用到的是PhoneWindow.setContentVIEw()。

Step2 PhoneWindow.setContentVIEw()

如果第一次调用mDecor和mContentParent对象都为null,会调用installDecor(),如果不是,则调用mContentParent.removeAllVIEws()来删除所有的子VIEw,然后inflate所以的VIEw,再添加到mContentParent中。

    public class PhoneWindow extends Window implements MenuBuilder.Callback {         @OverrIDe         public voID setContentVIEw(int layoutResID) {             //如果第一次调用mDecor和mContentParent对象都为null,会调用installDecor(),如果不是,则调用mContentParent.removeAllVIEws()             if (mContentParent == null) {                 installDecor();             } else {                 mContentParent.removeAllVIEws();             }             mLayoutInflater.inflate(layoutResID, mContentParent);             final Callback cb = getCallback();             if (cb != null && !isDestroyed()) {                 cb.onContentChanged();             }         }    }
Step2.1 PhoneWindow. installDecor()
    public class PhoneWindow extends Window implements MenuBuilder.Callback {            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();                    mTitleVIEw = (TextVIEw)findVIEwByID(com.androID.internal.R.ID.Title);                if (mTitleVIEw != null) {                    mTitleVIEw.setLayoutDirection(mDecor.getLayoutDirection());                    if ((getLocalFeatures() & (1 << FEATURE_NO_Title)) != 0) {                        VIEw TitleContainer = findVIEwByID(com.androID.internal.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);                    }                } else {                    mActionbar = (ActionbarVIEw) findVIEwByID(com.androID.internal.R.ID.action_bar);                    if (mActionbar != null) {                        mActionbar.setwindowCallback(getCallback());                        if (mActionbar.getTitle() == null) {                            mActionbar.setwindowTitle(mTitle);                        }                        final int localFeatures = getLocalFeatures();                        if ((localFeatures & (1 << FEATURE_PROGRESS)) != 0) {                            mActionbar.initProgress();                        }                        if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {                            mActionbar.initIndeterminateProgress();                        }                            final ActionbarOverlayLayout abol = (ActionbarOverlayLayout) findVIEwByID(                                com.androID.internal.R.ID.action_bar_overlay_layout);                        if (abol != null) {                            abol.setoverlayMode(                                    (localFeatures & (1 << FEATURE_ACTION_bar_OVERLAY)) != 0);                        }                            boolean splitactionbar = false;                        final boolean splitWhenNarrow =                                (mUiOptions & ActivityInfo.UIOPTION_SPliT_ACTION_bar_WHEN_NARROW) != 0;                        if (splitWhenNarrow) {                            splitactionbar = getContext().getResources().getBoolean(                                    com.androID.internal.R.bool.split_action_bar_is_narrow);                        } else {                            splitactionbar = getwindowstyle().getBoolean(                                    com.androID.internal.R.styleable.Window_windowsplitactionbar, false);                        }                        final ActionbarContainer splitVIEw = (ActionbarContainer) findVIEwByID(                                com.androID.internal.R.ID.split_action_bar);                        if (splitVIEw != null) {                            mActionbar.setSplitVIEw(splitVIEw);                            mActionbar.setSplitactionbar(splitactionbar);                            mActionbar.setSplitWhenNarrow(splitWhenNarrow);                                final ActionbarContextVIEw cab = (ActionbarContextVIEw) findVIEwByID(                                    com.androID.internal.R.ID.action_context_bar);                            cab.setSplitVIEw(splitVIEw);                            cab.setSplitactionbar(splitactionbar);                            cab.setSplitWhenNarrow(splitWhenNarrow);                        } else if (splitactionbar) {                            Log.e(TAG, "Requested split action bar with " +                                    "incompatible window decor! Ignoring request.");                        }                            if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||                                (mIconRes != 0 && !mActionbar.hasIcon())) {                            mActionbar.setIcon(mIconRes);                        } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&                                mIconRes == 0 && !mActionbar.hasIcon()) {                            mActionbar.setIcon(                                    getContext().getPackageManager().getDefaultActivityIcon());                            mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;                        }                        if ((mResourcesSetFlags & FLAG_RESOURCE_SET_logo) != 0 ||                                (mlogoRes != 0 && !mActionbar.haslogo())) {                            mActionbar.setlogo(mlogoRes);                        }                            // Post the panel invalIDate for later; avoID application onCreateOptionsMenu                        // being called in the mIDdle of onCreate or similar.                        mDecor.post(new Runnable() {                            public voID run() {                                // InvalIDate if the panel menu hasn't been created before this.                                PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);                                if (!isDestroyed() && (st == null || st.menu == null)) {                                    invalIDatePanelMenu(FEATURE_ACTION_bar);                                }                            }                        });                    }                }            }        }    }

首先判断mDecor是否为空,如果是空,则调用generateDecor()创建一个新的DecorVIEw赋值给mDecor,该类是一个FrameLayout的子类,是一个VIEwGroup,当用HIErarchyVIEwer查看Layoutt的时候每个窗口最顶层都有的一个FrameLayout,这个FrameLayout就是这边的这个DecorVIEw。

    protected DecorVIEw generateDecor() {        return new DecorVIEw(getContext(), -1);    }    private final class DecorVIEw extends FrameLayout implements RootVIEwSurfaceTaker {    }

然后判断mContentParent是否为空,如果为空,则调用generateLayout(mDecor)创建mContentParent。

    protected VIEwGroup generateLayout(DecorVIEw decor) {        // Apply data from current theme.                // 1. 从com.androID.internal.R.styleable.Window也就是androID:theme=“”配置的值中获取Window的Style属性        // 2. 通过requestFeature方法设置Window.mFeatures和PhoneWindow.mLocalFeatures属性,设置宽口风格                TypedArray a = getwindowstyle();        if (false) {            System.out.println("From style:");            String s = "Attrs:";            for (int i = 0; i < com.androID.internal.R.styleable.Window.length; i++) {                s = s + " " + Integer.toHexString(com.androID.internal.R.styleable.Window[i]) + "="                        + a.getString(i);            }            System.out.println(s);        }        mIsfloating = a.getBoolean(com.androID.internal.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(com.androID.internal.R.styleable.Window_windowNoTitle, false)) {            requestFeature(FEATURE_NO_Title);        } else if (a.getBoolean(com.androID.internal.R.styleable.Window_windowActionbar, false)) {            // Don't allow an action bar if there is no Title.            requestFeature(FEATURE_ACTION_bar);        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowActionbarOverlay, false)) {            requestFeature(FEATURE_ACTION_bar_OVERLAY);        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowActionModeOverlay, false)) {            requestFeature(FEATURE_ACTION_MODE_OVERLAY);        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowFullscreen, false)) {            setFlags(FLAG_FulLSCREEN, FLAG_FulLSCREEN & (~getForceDWindowFlags()));        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowTranslucentStatus,                false)) {            setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS                    & (~getForceDWindowFlags()));        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowTranslucentNavigation,                false)) {            setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION                    & (~getForceDWindowFlags()));        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowOverscan, false)) {            setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForceDWindowFlags()));        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowshowWallpaper, false)) {            setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForceDWindowFlags()));        }        if (a.getBoolean(com.androID.internal.R.styleable.Window_windowEnableSplittouch,                getContext().getApplicationInfo().targetSdkVersion                        >= androID.os.Build.VERSION_CODES.HONEYCOMB)) {            setFlags(FLAG_SPliT_touch, FLAG_SPliT_touch&(~getForceDWindowFlags()));        }        a.getValue(com.androID.internal.R.styleable.Window_windowMinWIDthMajor, mMinWIDthMajor);        a.getValue(com.androID.internal.R.styleable.Window_windowMinWIDthMinor, mMinWIDthMinor);        if (a.hasValue(com.androID.internal.R.styleable.Window_windowFixeDWIDthMajor)) {            if (mFixeDWIDthMajor == null) mFixeDWIDthMajor = new TypedValue();            a.getValue(com.androID.internal.R.styleable.Window_windowFixeDWIDthMajor,                    mFixeDWIDthMajor);        }        if (a.hasValue(com.androID.internal.R.styleable.Window_windowFixeDWIDthMinor)) {            if (mFixeDWIDthMinor == null) mFixeDWIDthMinor = new TypedValue();            a.getValue(com.androID.internal.R.styleable.Window_windowFixeDWIDthMinor,                    mFixeDWIDthMinor);        }        if (a.hasValue(com.androID.internal.R.styleable.Window_windowFixedHeightmajor)) {            if (mFixedHeightmajor == null) mFixedHeightmajor = new TypedValue();            a.getValue(com.androID.internal.R.styleable.Window_windowFixedHeightmajor,                    mFixedHeightmajor);        }        if (a.hasValue(com.androID.internal.R.styleable.Window_windowFixedHeightminor)) {            if (mFixedHeightminor == null) mFixedHeightminor = new TypedValue();            a.getValue(com.androID.internal.R.styleable.Window_windowFixedHeightminor,                    mFixedHeightminor);        }        // 3.读取SDK版本信息        final Context context = getContext();        final int targetSdk = context.getApplicationInfo().targetSdkVersion;        final boolean targetPreHoneycomb = targetSdk < androID.os.Build.VERSION_CODES.HONEYCOMB;        final boolean targetPreIcs = targetSdk < androID.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;        final boolean targetHcNeedsOptions = context.getResources().getBoolean(                com.androID.internal.R.bool.target_honeycomb_needs_options_menu);        final boolean noActionbar = !hasFeature(FEATURE_ACTION_bar) || hasFeature(FEATURE_NO_Title);        if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionbar)) {            addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);        } else {            clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);        }                if (mAlwaysReadCloSEOntouchAttr || getContext().getApplicationInfo().targetSdkVersion                >= androID.os.Build.VERSION_CODES.HONEYCOMB) {            if (a.getBoolean(                    com.androID.internal.R.styleable.Window_windowCloSEOntouchOutsIDe,                    false)) {                setCloSEOntouchOutsIDeIfNotSet(true);            }        }                // 4. 获取LayoutParams信息用来判断是否输入法、是否模糊后面的,是否有窗口动画        WindowManager.LayoutParams params = getAttributes();        if (!hasSoftinputMode()) {            params.softinputMode = a.getInt(                    com.androID.internal.R.styleable.Window_windowsoftinputMode,                    params.softinputMode);        }        if (a.getBoolean(com.androID.internal.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);            }        }        if (params.windowAnimations == 0) {            params.windowAnimations = a.getResourceID(                    com.androID.internal.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(                            com.androID.internal.R.styleable.Window_windowBackground, 0);                }                if (mFrameResource == 0) {                    mFrameResource = a.getResourceID(com.androID.internal.R.styleable.Window_windowFrame, 0);                }                if (false) {                    System.out.println("Background: "                            + Integer.toHexString(mBackgroundResource) + " Frame: "                            + Integer.toHexString(mFrameResource));                }            }            mTextcolor = a.getcolor(com.androID.internal.R.styleable.Window_textcolor, 0xFF000000);        }        // Inflate the window decor.        // 5. 获取上面设置的PhoneWindow.mLocalFeatures,根据一些列的条件判断需要是哪个layoutResource,比如是否是全屏,是否有标题栏        // 有如下7种类型的layout:        // com.androID.internal.R.layout.screen_Title_icons        // com.androID.internal.R.layout.screen_progress        // com.androID.internal.R.layout.screen_custom_Title        // com.androID.internal.R.layout.screen_action_bar        // com.androID.internal.R.layout.screen_Title        // com.androID.internal.R.layout.screen_simple_overlay_action_mode        // com.androID.internal.R.layout.screen_simple                int layoutResource;        int features = getLocalFeatures();        // System.out.println("Features: 0x" + Integer.toHexString(features));        if ((features & ((1 << FEATURE_left_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {            if (mIsfloating) {                TypedValue res = new TypedValue();                getContext().gettheme().resolveAttribute(                        com.androID.internal.R.attr.dialogTitleIconsDecorLayout, res, true);                layoutResource = res.resourceID;            } else {                layoutResource = com.androID.internal.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 = com.androID.internal.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(                        com.androID.internal.R.attr.dialogCustomTitleDecorLayout, res, true);                layoutResource = res.resourceID;            } else {                layoutResource = com.androID.internal.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(                        com.androID.internal.R.attr.dialogTitleDecorLayout, res, true);                layoutResource = res.resourceID;            } else if ((features & (1 << FEATURE_ACTION_bar)) != 0) {                layoutResource = com.androID.internal.R.layout.screen_action_bar;            } else {                layoutResource = com.androID.internal.R.layout.screen_Title;            }            // System.out.println("Title!");        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {            layoutResource = com.androID.internal.R.layout.screen_simple_overlay_action_mode;        } else {            // Embedded, so no decoration is needed.            layoutResource = com.androID.internal.R.layout.screen_simple;            // System.out.println("Simple!");        }        mDecor.startChanging();        // 6. 填充相应的layoutResource,并把它加到decor里面        VIEw in = mLayoutInflater.inflate(layoutResource, null);        decor.addVIEw(in, new VIEwGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));        // 7. 找出相应的ID_ANDROID_CONTENT的VIEwGroup,实际想就是上面layoutResource里面的<FrameLayout androID:ID="@androID:ID/content" /> 这个FrameLayout        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);            }        }        // Remaining setup -- of background and Title -- that only applIEs        // to top-level windows.        if (getContainer() == null) {            Drawable drawable = mBackgroundDrawable;            if (mBackgroundResource != 0) {                drawable = getContext().getResources().getDrawable(mBackgroundResource);            }            mDecor.setwindowBackground(drawable);            drawable = null;            if (mFrameResource != 0) {                drawable = getContext().getResources().getDrawable(mFrameResource);            }            mDecor.setwindowFrame(drawable);            // System.out.println("Text=" + Integer.toHexString(mTextcolor) +            // " Sel=" + Integer.toHexString(mTextSelectedcolor) +            // " title=" + Integer.toHexString(mTitlecolor));            if (mTitlecolor == 0) {                mTitlecolor = mTextcolor;            }            if (mTitle != null) {                setTitle(mTitle);            }            setTitlecolor(mTitlecolor);        }        mDecor.finishChanging();        return contentParent;    }

此时,我们拿一个常用的com.androID.internal.R.layout.screen_Title窗口布局文件来分析一下。
这个窗口布局文件分为3个部分:

action mode 标题栏内容区域 Activity的SetContentVIEw的Layout文件实际放置的俯视图就是这个ID为conten的FrameLayout
    <linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"        androID:fitsSystemwindows="true"        androID:orIEntation="vertical"        androID:layout_wIDth="match_parent"        androID:layout_height="match_parent">        <!-- Popout bar for action modes -->        <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" />        <relativeLayout androID:ID="@androID:ID/Title_container"                        androID:layout_wIDth="match_parent"            androID:layout_height="?androID:attr/windowTitleSize">            <!-- The Title background has 9px left padding. -->            <ImageVIEw androID:ID="@androID:ID/left_icon"                androID:visibility="gone"                androID:layout_marginEnd="9dip"                androID:layout_wIDth="16dip"                androID:layout_height="16dip"                androID:scaleType="fitCenter"                androID:layout_alignParentStart="true"                androID:layout_centerVertical="true" />            <Progressbar androID:ID="@+ID/progress_circular"                                androID:visibility="gone"                androID:max="10000"                androID:layout_centerVertical="true"                androID:layout_alignParentEnd="true"                androID:layout_marginStart="6dip"                androID:layout_wIDth="wrap_content"                androID:layout_height="wrap_content" />            <!-- There are 6dip between this and the circular progress on the right, we                 also make 6dip (with the -3dip margin_left) to the icon on the left or                 the screen left edge if no icon. This also places our left edge 3dip to                 the left of the Title text left edge. -->            <Progressbar androID:ID="@+ID/progress_horizontal"                                androID:layout_wIDth="match_parent"                androID:layout_height="wrap_content"                androID:layout_marginStart="-3dip"                androID:layout_toStartOf="@androID:ID/progress_circular"                androID:layout_toEndOf="@androID:ID/left_icon"                androID:layout_centerVertical="true"                androID:visibility="gone"                androID:max="10000" />            <linearLayout                androID:layout_wIDth="match_parent"                androID:layout_height="match_parent"                androID:orIEntation="horizontal"                androID:layout_toStartOf="@ID/progress_circular"                androID:layout_toEndOf="@androID:ID/left_icon"                >                <TextVIEw androID:ID="@androID:ID/Title"                                        androID:layout_wIDth="0dip"                    androID:layout_height="match_parent"                    androID:layout_weight="1"                    androID:background="@null"                    androID:fadingEdge="horizontal"                    androID:scrollHorizontally="true"                    androID:gravity="center_vertical"                    androID:layout_marginEnd="2dip"                    />                <!-- 2dip between the icon and the Title text, if icon is present. -->                <ImageVIEw androID:ID="@androID:ID/right_icon"                    androID:visibility="gone"                    androID:layout_wIDth="16dip"                    androID:layout_height="16dip"                    androID:layout_weight="0"                    androID:layout_gravity="center_vertical"                    androID:scaleType="fitCenter"                    />                </linearLayout>        </relativeLayout>        <FrameLayout androID:ID="@androID:ID/content"            androID:layout_wIDth="match_parent"            androID:layout_height="0dip"            androID:layout_weight="1"            androID:foregroundGravity="fill_horizontal|top"            androID:foreground="?androID:attr/windowContentOverlay" />    </linearLayout>
Step2.2 LayoutInflater.inflate()

前一步结束之后,我们需要的mDecor和mContentParent都已经初始化完毕,mContentParent( )就是我们Activity中setContentVIEw的视图所要填充到的父视图。

    public VIEw inflate(int resource, VIEwGroup root) {        return inflate(resource, root, root != null);    }    public VIEw inflate(XmlPullParser parser, VIEwGroup root) {        return inflate(parser, root, root != null);    }    public VIEw inflate(int resource, VIEwGroup root, boolean attachToRoot) {        if (DEBUG) System.out.println("INFLATING from resource: " + resource);        XmlResourceParser parser = getContext().getResources().getLayout(resource);        try {            return inflate(parser, root, attachtoroot);        } finally {            parser.close();        }    }    public vIEw inflate(xmlpullparser parser, vIEwgroup root, boolean attachtoroot) {        synchronized (mconstructorargs) {            trace.tracebegin(trace.trace_tag_vIEw, "inflate");            final attributeset attrs = xml.asattributeset(parser);            context lastcontext = (context)mconstructorargs[0];            mconstructorargs[0] = mcontext;            vIEw result = root;            try {                // 1. 查找并初始化跟试图节点                // look for the root node.                                ……                final string name = parser.getname();                                if (tag_merge.equals(name)) {                    if (root == null || !attachtoroot) {                        throw new inflateexception("<merge /> can be used only with a valID "                                + "vIEwgroup root and attachtoroot=true");                    }                    rinflate(parser, root, attrs, false);                } else {                    // temp is the root vIEw that was found in the xml                    vIEw temp;                    if (tag_1995.equals(name)) {                        temp = new blinklayout(mcontext, attrs);                    } else {                        temp = createvIEwfromtag(root, name, attrs);                    }                    vIEwgroup.layoutparams params = null;                    if (root != null) {                        if (deBUG) {                            system.out.println("creating params from root: " +                                    root);                        }                        // create layout params that match root, if supplIEd                        params = root.generatelayoutparams(attrs);                        if (!attachtoroot) {                            // set the layout params for temp if we are not                            // attaching. (if we are, we use addvIEw, below)                            temp.setlayoutparams(params);                        }                    }                    if (deBUG) {                        system.out.println("-----> start inflating children");                    }                    // 创建所有的子试图节点                    // inflate all children under temp                    rinflate(parser, temp, attrs, true);                                        ……                }            } catch (xmlpullparserexception e) {                inflateexception ex = new inflateexception(e.getmessage());                ex.initcause(e);                throw ex;            } catch (ioexception e) {                inflateexception ex = new inflateexception(                        parser.getpositiondescription()                        + ": " + e.getmessage());                ex.initcause(e);                throw ex;            } finally {                // don't retain static reference on context.                mconstructorargs[0] = lastcontext;                mconstructorargs[1] = null;            }            trace.traceend(trace.trace_tag_vIEw);            return result;        }    }

实际上mLayoutInflater实际上是PhoneLayoutInflater的对象,可以分析Step1中PhoneWindow的初始化过程得知。可以看如下代码:

    public class PhoneWindow extends Window implements MenuBuilder.Callback {        public PhoneWindow(Context context) {            super(context);            mLayoutInflater = LayoutInflater.from(context);        }    }        public abstract class LayoutInflater {        public static LayoutInflater from(Context context) {            LayoutInflater LayoutInflater =                    (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);            if (LayoutInflater == null) {                throw new AssertionError("LayoutInflater not found.");            }            return LayoutInflater;        }    }        class ContextImpl extends Context {        static {            registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {                    public Object createService(ContextImpl ctx) {                        return PolicyManager.makeNewLayoutInflater(ctx.getouterContext());                    }});        }                private static final HashMap<String, ServiceFetcher> SYstem_SERVICE_MAP =        new HashMap<String, ServiceFetcher>();        private static int sNextPerContextServiceCacheIndex = 0;        private static voID registerService(String servicename, ServiceFetcher fetcher) {            if (!(fetcher instanceof StaticServiceFetcher)) {                fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;            }            SYstem_SERVICE_MAP.put(servicename, fetcher);        }        public Object getSystemService(String name) {            ServiceFetcher fetcher = SYstem_SERVICE_MAP.get(name);            return fetcher == null ? null : fetcher.getService(this);        }    }        public final class PolicyManager {        private static final String POliCY_IMPL_CLASS_name =            "com.androID.internal.policy.impl.Policy";            private static final IPolicy sPolicy;            static {            // Pull in the actual implementation of the policy at run-time            try {                Class policyClass = Class.forname(POliCY_IMPL_CLASS_name);                sPolicy = (IPolicy)policyClass.newInstance();            }             ……        }        public static LayoutInflater makeNewLayoutInflater(Context context) {            return sPolicy.makeNewLayoutInflater(context);        }    }    public class Policy implements IPolicy {        public LayoutInflater makeNewLayoutInflater(Context context) {            return new PhoneLayoutInflater(context);        }    }
至此,总的流程都已经结束了,我们的Acitivity.setContentVIEw就差不多分析完毕了。总的来说上面的过程可以概括为3步:

1、创建一个DecorVIEw对象,该对象将作为整个应用窗口的根视图
2、创建不同的窗口布局文件,并且获取Activity的布局文件该存放的地方,即该窗口布局文件内ID为content的FrameLayout指定() 。
3、将Activity的布局文件添加至ID为content的FrameLayout内。
----

3. 最后我们来分析一下每一个VIEw或者VIEwGroup是如何被创建的。

从上面我们可以得知,每一个VIEw或者VIEwGroup都是通过调用LayoutInflater.createvIEwfromtag()来进行VIEw的穿件

    VIEw createVIEwFromTag(VIEw parent, String name, AttributeSet attrs) {        if (name.equals("vIEw")) {            name = attrs.getAttributeValue(null, "class");        }        if (DEBUG) System.out.println("******** Creating vIEw: " + name);        try {            VIEw vIEw;            // 此处几个Factory都不会执行            if (mFactory2 != null) vIEw = mFactory2.onCreateVIEw(parent, name, mContext, attrs);            else if (mFactory != null) vIEw = mFactory.onCreateVIEw(name, mContext, attrs);            else vIEw = null;            if (vIEw == null && mPrivateFactory != null) {                vIEw = mPrivateFactory.onCreateVIEw(parent, name, mContext, attrs);            }            if (vIEw == null) {            // 根据VIEw是否是内置判断需要调用的方法:            // 如果是内置的(androID.Widget或androID.webkit或andriod.vIEw包里的)androID自身类就调用LayoutInflater.onCreateVIEw (3parameters),如果不是就调用LayoutInflater.createVIEw            如果不是内置(自定义的,或者目录不在上述几个包中的)则调用LayoutInflater.createVIEw(name, null, attrs);                if (-1 == name.indexOf('.')) {                    vIEw = onCreateVIEw(parent, name, attrs);                } else {                    vIEw = createVIEw(name, null, attrs);                }            }            if (DEBUG) System.out.println("Created vIEw is: " + vIEw);            return vIEw;        ……    }

根据VIEw是否是内置判断需要调用的方法:
如果是内置的(androID.Widget或androID.webkit或andriod.vIEw包里的)androID自身类就调用LayoutInflater.onCreateVIEw (3parameters),如果不是就调用LayoutInflater.createVIEw;
如果不是内置(自定义的,或者目录不在上述几个包中的)则调用LayoutInflater.createVIEw(name, null, attrs);
如果是内置的(androID.Widget或androID.webkit)androID自身类就调用LayoutInflater.createVIEw,如果不是就调用LayoutInflater.onCreateVIEw(2 parameters);

    public abstract class LayoutInflater {        protected VIEw onCreateVIEw(String name, AttributeSet attrs)                throws ClassNotFoundException {            return createVIEw(name, "androID.vIEw.", attrs);        }            protected VIEw onCreateVIEw(VIEw parent, String name, AttributeSet attrs)                throws ClassNotFoundException {            // 1. 根据多态性,直接调用PhoneLayoutInflater.onCreateVIEw(2 parameters)            return onCreateVIEw(name, attrs);        }    }        public class PhoneLayoutInflater extends LayoutInflater {        private static final String[] sClassprefixList = {            "androID.Widget.",            "androID.webkit."        };        @OverrIDe protected VIEw onCreateVIEw(String name, AttributeSet attrs) throws ClassNotFoundException {            // 2. 如果是内置的(androID.Widget或androID.webkit)androID自身类就调用LayoutInflater.createVIEw,如果不是就调用LayoutInflater.onCreateVIEw(2 parameters)            for (String prefix : sClassprefixList) {                try {                    VIEw vIEw = createVIEw(name, prefix, attrs);                    if (vIEw != null) {                        return vIEw;                    }                } catch (ClassNotFoundException e) {                    // In this case we want to let the base class take a crack                    // at it.                }            }                // 2.             return super.onCreateVIEw(name, attrs);        }    }        不过最终都是要调用createVIEw()方法来进行VIEw或者VIEwGroup的创建。createVIEw()的方法气势很简答,就是通过反射机制把VIEw或者VIEwGroup给创建出来。        public final VIEw createVIEw(String name, String prefix, AttributeSet attrs)            throws ClassNotFoundException, InflateException {        // 1. 如果sConstructorMap里面已经有对应的类,则直接取出来,        // 如果没有,则通过发射机制把对应的类给loadClass进来;        Constructor<? extends VIEw> constructor = sConstructorMap.get(name);        Class<? extends VIEw> clazz = null;        try {            Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);            if (constructor == null) {                // Class not found in the cache, see if it's real, and try to add it                clazz = mContext.getClassLoader().loadClass(                        prefix != null ? (prefix + name) : name).asSubclass(VIEw.class);                                if (mFilter != null && clazz != null) {                    boolean allowed = mFilter.onLoadClass(clazz);                    if (!allowed) {                        failNotAllowed(name, prefix, attrs);                    }                }                constructor = clazz.getConstructor(mConstructorSignature);                sConstructorMap.put(name, constructor);            } else {                // If we have a filter, apply it to cached constructor                if (mFilter != null) {                    // Have we seen this name before?                    Boolean allowedState = mFilterMap.get(name);                    if (allowedState == null) {                        // New class -- remember whether it is allowed                        clazz = mContext.getClassLoader().loadClass(                                prefix != null ? (prefix + name) : name).asSubclass(VIEw.class);                                                boolean allowed = clazz != null && mFilter.onLoadClass(clazz);                        mFilterMap.put(name, allowed);                        if (!allowed) {                            failNotAllowed(name, prefix, attrs);                        }                    } else if (allowedState.equals(Boolean.FALSE)) {                        failNotAllowed(name, prefix, attrs);                    }                }            }            Object[] args = mConstructorArgs;            args[1] = attrs;            // 2. 创建对应的VIEw或者VIEwGroup对象。            constructor.setAccessible(true);            final VIEw vIEw = constructor.newInstance(args);            if (vIEw instanceof VIEwStub) {                // always use ourselves when inflating VIEwStub later                final VIEwStub vIEwStub = (VIEwStub) vIEw;                vIEwStub.setLayoutInflater(this);            }            return vIEw;        }        ……    }

转载于:https://www.cnblogs.com/GMCisMarkdownCraftsman/p/3754407.HTML

总结

以上是内存溢出为你收集整理的从setContentView()谈起全部内容,希望文章能够帮你解决从setContentView()谈起所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1115488.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-29
下一篇 2022-05-29

发表评论

登录后才能评论

评论列表(0条)

保存