上一篇博客Android中Handler原理在讲到Handler的时候谈到了android的Activity启动是如何执行到onCreate方法的,这篇主要从onCreate方法里面我们必须要写的方法setContentView开始,研究布局视图是如何加载到手机窗口上的。

当在执行到setContentView时,实际上执行的是

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

可以看到实际上是Window类的setContentView方法

private Window mWindow;public Window getWindow() {        return mWindow;}

Window类是一个抽象类,下面主要是找到他的实现类。mWindow初始化在

final void attach(……) {        ……        mWindow = PolicyManager.makeNewWindow(this);        mWindow.setCallback(this);        mWindow.getLayoutInflater().setPrivateFactory(this);……    }

Attach方法在main方法中。具体查看上一篇博客。调用了PolicyManager类的静态方法makeNewWindow生成Window对象

private static final String POLICY_IMPL_CLASS_NAME =        "com.android.internal.policy.impl.Policy";private static final IPolicy sPolicy;static {        try {            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);            sPolicy = (IPolicy)policyClass.newInstance();        }……    }public static Window makeNewWindow(Context context) {        return sPolicy.makeNewWindow(context);}

可以看到是通过Policy类的makeNewWindow方法得到的Window对象,这里是通过反射机制获取的Policy的实例。

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

可以看到实际上是一个PhoneWindow。那么根据多态,其实在上面调用的就是PhoneWindow#setContentWindow

public void setContentView(int layoutResID) {        if (mContentParent == null) {            installDecor();//1        } else {            mContentParent.removeAllViews();        }        mLayoutInflater.inflate(layoutResID, mContentParent);//2 将layoutResID填充,他的父View是mContentParent是在installDecor方法里面mContentParent = generateLayout(mDecor);得到的        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            cb.onContentChanged();        }}

执行到installDecor()

private void installDecor() {    if (mDecor == null) {        mDecor = generateDecor();//生成装饰窗口,装饰窗口继承自FrameLayout        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);        mDecor.setIsRootNamespace(true);        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);        }    }    if (mContentParent == null) {        mContentParent = generateLayout(mDecor);// 产生布局,返回父布局,暂时这样理解,具体进去看代码        mDecor.makeOptionalFitsSystemWindows();        mTitleView = (TextView)findViewById(com.android.internal.R.id.title);        ......        }    }}

generateLayout的代码如下

protected ViewGroup generateLayout(DecorView decor) {        // Apply data from current theme.        TypedArray a = getWindowStyle();// 获取当前设置的主题......        if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {            requestFeature(FEATURE_NO_TITLE);//可以看到平时在AndroidManifest配置的窗口等各其实在代码里都是在这里修改的        } 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);        }......//19-63行根据我们指定的有无标题等各种窗口风格得到对应的默认布局,//这些布局在D:\SoftWare\Java\android4.2-source\frameworks\base\core\res\res\layout        int layoutResource;        int features = getLocalFeatures();        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;            }            removeFeature(FEATURE_ACTION_BAR);        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {            layoutResource = com.android.internal.R.layout.screen_progress;        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {            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;            }            removeFeature(FEATURE_ACTION_BAR);        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {            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) {                if ((features & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0) {                    layoutResource = com.android.internal.R.layout.screen_action_bar_overlay;                } else {                    layoutResource = com.android.internal.R.layout.screen_action_bar;                }            } else {                layoutResource = com.android.internal.R.layout.screen_title;            }        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {            layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;        } else {            layoutResource = com.android.internal.R.layout.screen_simple;        }        mDecor.startChanging();        View in = mLayoutInflater.inflate(layoutResource, null);//根据上面的判断选择的layoutResource填充成View        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));//调用装饰窗口的addView方法将上一步生成的View添加到最外层的装饰窗口        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//ID_ANDROID_CONTENT对应的都是@android:id/content其实是一个FrameLayout        ......        mDecor.finishChanging();        return contentParent;    }

下面是最常用的layoutResource布局文件他们在D:\SoftWare\Java\android4.2-source\frameworks\base\core\res\res\layout文件夹下

Screen-title.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:fitsSystemWindows="true">    <!-- 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" />    <FrameLayout        android:layout_width="match_parent"         android:layout_height="?android:attr/windowTitleSize"        style="?android:attr/windowTitleBackgroundStyle">        <TextView android:id="@android:id/title"             style="?android:attr/windowTitleStyle"            android:background="@null"            android:fadingEdge="horizontal"            android:gravity="center_vertical"            android:layout_width="match_parent"            android:layout_height="match_parent" />    </FrameLayout>    <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>

最外层是线性布局,包含帧布局(包含一个TextView其实就是标题)和帧布局。其实这个就是最常见的样子。默认生成的程序就是这个样子。

Screen-simple.xml

<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" />    <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>

显而易见这个就是全屏设置时默认加载的布局。

我们可以看到id为content的FrameLayout都存在的,因为他要装载我们填充的xml

依Screen-title.xml为例,大致是这样子的


通过以上分析明白了以下几点:

1. Activity呈现出来的界面其实是一个PhoneWindow类在管理的,这个类中有一个DecorView成员就是最外层的一个容器。

2. 上面这张图是非常重要的,显示了窗口的结构。

3. Activity到底是个什么东西?还真不好说清楚…^_^总之和刚开始的认识是不同的。

4. 遇到不懂得问题就去查看源码。代码是最好的老师!









更多相关文章

  1. Android高手进阶教程(十一)--Android(安卓)通用获取Ip的方法(判
  2. CardView 添加背景图片、改变颜色、水波纹效果的方法
  3. Android取消EditText自动聚焦、自动弹出输入法的方法
  4. Android(安卓)Studio之工程中导入jni库方法
  5. Android采用KSOAP2访问webservice
  6. 详解 Android(安卓)的 Activity 组件
  7. Android(安卓)学习路线
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android基于特征码查杀手机病毒
  2. android 横向切换 activity
  3. android ListView性能优化提示
  4. android 开机自动启动
  5. android 中的 pathview 效果
  6. Android(安卓)Porting
  7. Android(安卓)UI控件详解-RadioGroup和Ra
  8. Android设置系统时间
  9. Android(安卓)debuggerd
  10. Talking about Android(安卓)Process