android 中view 代表一块图形区域。每一个view 都与一个依赖一个父view。在每一个Activity 中有一个Window 代表一个屏幕,
包含一个View 树和窗口的layout 参数。View tree的root View可以通过getDecorView得到。 在 new 一个activity 时,通常把APK的view和布局通过setContentView(R.layout.activity_main)设置到View树中。
一.在activity中有一个: private Window mWindow; 看一看这个mWindow是怎么来的:在Activity 的attach函数中:
追踪一下这个函数,看一下调用流程:
./frameworks/base/core/java/com/android/internal/policy/PolicyManager.java:
这是一个 final 类,通过反射的方法获取一个com.android.internal.policy.impl.Policy类的静态对象:sPolicy,调用这个类的makeNewWindow:
./frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java
在这个类中返回了new PhoneWindow(context);
./frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java 现在我们找到了这个Window 对象。Window 的庐山真面目:
继承自 Window。window 的关系搞清楚了。
二.在Activity中通过mWindow.getDecorView() 获取activity view树的布局。又来到了window 中。
DecorView 是PhoneWindow的一个内部类:
其实就是一个FrameLayout 布局,FrameLayout extend ViewGroup。所有Activity 中的view 都添加到这个布局中。installDecor 函数:
这就是在PhoneWindow 的mDecorView 。需要注意一下mContentParent 这个变量。下面会分析到。
总结一下在一个Activity 中,有一个PhoneWindwo 对象,这个对象有有一个内部类Decorview ,Decorview extend FrameLayout extend ViewGroup 。这个Activity 的 view 都保存在这里,形成一个View 树。
三.
Activity 的 setContentView:
PhoneWindow 的setContentView:
mLayoutInflater.inflate(layoutResID, mContentParent); 在这行代码中,view 被设置进了mContentParent 这个父View中,在 PhoneWindow 中:
private ViewGroup mContentParent
在刚才分析DecorView的时候, 在installDecor中会调用 mContentParent = generateLayout ( mDecor ), 生成mContentParent;看一下实现:
一开始获取一些窗口的属性,然后根据这些属性确定 layoutResource 的值,layoutResource 为com.android.internal.R.layout.screen_开头;就是 framework-res.apk里面的资源:src/android$ ls frameworks/base/core/res/res/layout/screen*
frameworks/base/core/res/res/layout/screen_action_bar.xml frameworks/base/core/res/res/layout/screen_simple.xml
frameworks/base/core/res/res/layout/screen_custom_title.xml frameworks/base/core/res/res/layout/screen_title_icons.xml
frameworks/base/core/res/res/layout/screen_progress.xml frameworks/base/core/res/res/layout/screen_title.xml
frameworks/base/core/res/res/layout/screen_simple_overlay_action_mode.xml frameworks/base/core/res/res/layout/screen.xml
然后解析:
contentParent 就是这些xml 文件里的一个ID_ANDROID_CONTENT 的view 。查找 ID_ANDROID_CONTENT定义:
frameworks/base/core/java/android/view/Window.java 124行:
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
打开 screen.xml 文件:
content 是一个FrameLayout的布局,在这几个screen_*.xml文件中 都有一个id为:content的View。也就是说 mDecorView 是一个Activity的根布局,contentParent是mDecorView 一个子布局,提供给程序员的View的根布局。setContentView 的时候以contentParent为父节点。
四.
Activity的默认布局确定了,可以确定一下,修改xml 布局:
当我们进入桌面的时候,桌面效果如下:
homeshell.png
进入HelloWorld,没有任何变化。分析generateLayout的时候已经看到会根据窗口的属性选择不同的资源文件。桌面和一般的Activity使用了不同的资源配置。
修改screen_action_bar.xml
HelloWorld 的效果:
activity.png
从图中可以看到根布局是一个FrameLayout布局,就是mDecorView.DecorView extend FrameLayout。 被选中的区域为FrameLayout,就是mcontentParent,mcontentParent中有一个RelativeLayout,是我们setContentView 的R.layout.activity_main 布局文件。
阅读(2053) | 评论(0) | 转发(0) |
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
一.在activity中有一个: private Window mWindow; 看一看这个mWindow是怎么来的:在Activity 的attach函数中:
点击(此处)折叠或打开
- mWindow = PolicyManager.makeNewWindow(this);
./frameworks/base/core/java/com/android/internal/policy/PolicyManager.java:
点击(此处)折叠或打开
- package com.android.internal.policy;
-
- import android.content.Context;
- import android.view.FallbackEventHandler;
- import android.view.LayoutInflater;
- import android.view.Window;
- import android.view.WindowManagerPolicy;
-
- import com.android.internal.policy.IPolicy;
-
- /**
- * {@hide}
- */
-
- 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();
- } catch (ClassNotFoundException ex) {
- throw new RuntimeException(
- POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
- } catch (InstantiationException ex) {
- throw new RuntimeException(
- POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
- } catch (IllegalAccessException ex) {
- throw new RuntimeException(
- POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
- }
- }
-
- // Cannot instantiate this class
- private PolicyManager() {}
-
- // The static methods to spawn new policy-specific objects
- public static Window makeNewWindow(Context context) {
- return sPolicy.makeNewWindow(context);
- }
-
- public static LayoutInflater makeNewLayoutInflater(Context context) {
- return sPolicy.makeNewLayoutInflater(context);
- }
-
- public static WindowManagerPolicy makeNewWindowManager() {
- return sPolicy.makeNewWindowManager();
- }
-
- public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
- return sPolicy.makeNewFallbackEventHandler(context);
- }
- }
./frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java
点击(此处)折叠或打开
- package com.android.internal.policy.impl;
-
- import android.content.Context;
- import android.util.Log;
- import android.view.FallbackEventHandler;
- import android.view.LayoutInflater;
- import android.view.Window;
- import android.view.WindowManagerPolicy;
-
- import com.android.internal.policy.IPolicy;
- import com.android.internal.policy.impl.PhoneLayoutInflater;
- import com.android.internal.policy.impl.PhoneWindow;
- import com.android.internal.policy.impl.PhoneWindowManager;
-
- /**
- * {@hide}
- */
-
- // Simple implementation of the policy interface that spawns the right
- // set of objects
- public class Policy implements IPolicy {
- private static final String TAG = "PhonePolicy";
-
- private static final String[] preload_classes = {
- "com.android.internal.policy.impl.PhoneLayoutInflater",
- "com.android.internal.policy.impl.PhoneWindow",
- "com.android.internal.policy.impl.PhoneWindow$1",
- "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
- "com.android.internal.policy.impl.PhoneWindow$DecorView",
- "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
- "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
- };
-
- static {
- // For performance reasons, preload some policy specific classes when
- // the policy gets loaded.
- for (String s : preload_classes) {
- try {
- Class.forName(s);
- } catch (ClassNotFoundException ex) {
- Log.e(TAG, "Could not preload class for phone policy: " + s);
- }
- }
- }
-
- public Window makeNewWindow(Context context) {
- return new PhoneWindow(context);
- }
-
- public LayoutInflater makeNewLayoutInflater(Context context) {
- return new PhoneLayoutInflater(context);
- }
-
- public WindowManagerPolicy makeNewWindowManager() {
- return new PhoneWindowManager();
- }
-
- public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
- return new PhoneFallbackEventHandler(context);
- }
- }
./frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java 现在我们找到了这个Window 对象。Window 的庐山真面目:
点击(此处)折叠或打开
- public class PhoneWindow extends Window implements MenuBuilder.Callback {
二.在Activity中通过mWindow.getDecorView() 获取activity view树的布局。又来到了window 中。
点击(此处)折叠或打开
- public final View getDecorView() {
- if (mDecor == null) {
- installDecor();
- }
- return mDecor;
- }
点击(此处)折叠或打开
- private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
点击(此处)折叠或打开
- 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);
- ......
- }
点击(此处)折叠或打开
- protected DecorView generateDecor() {
- return new DecorView(getContext(), -1);
- }
这就是在PhoneWindow 的mDecorView 。需要注意一下mContentParent 这个变量。下面会分析到。
总结一下在一个Activity 中,有一个PhoneWindwo 对象,这个对象有有一个内部类Decorview ,Decorview extend FrameLayout extend ViewGroup 。这个Activity 的 view 都保存在这里,形成一个View 树。
三.
Activity 的 setContentView:
点击(此处)折叠或打开
- public void setContentView(int layoutResID) {
- getWindow().setContentView(layoutResID);
- initActionBar();
- }
点击(此处)折叠或打开
- public void setContentView(int layoutResID) {
- if (mContentParent == null) {
- installDecor();
- } else {
- mContentParent.removeAllViews();
- }
- mLayoutInflater.inflate(layoutResID, mContentParent);
- final Callback cb = getCallback();
- if (cb != null && !isDestroyed()) {
- cb.onContentChanged();
- }
- }
private ViewGroup mContentParent
在刚才分析DecorView的时候, 在installDecor中会调用 mContentParent = generateLayout ( mDecor ), 生成mContentParent;看一下实现:
点击(此处)折叠或打开
- protected ViewGroup generateLayout(DecorView decor) {
- // Apply data from current theme.
- ......
-
- // Inflate the window decor.
-
- 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;
- System.out.println("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();
-
- View in = mLayoutInflater.inflate(layoutResource, null);
- decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
- 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;
- }
frameworks/base/core/res/res/layout/screen_action_bar.xml frameworks/base/core/res/res/layout/screen_simple.xml
frameworks/base/core/res/res/layout/screen_custom_title.xml frameworks/base/core/res/res/layout/screen_title_icons.xml
frameworks/base/core/res/res/layout/screen_progress.xml frameworks/base/core/res/res/layout/screen_title.xml
frameworks/base/core/res/res/layout/screen_simple_overlay_action_mode.xml frameworks/base/core/res/res/layout/screen.xml
- View in = mLayoutInflater.inflate(layoutResource, null);
- decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
- ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
- if (contentParent == null) {
- throw new RuntimeException("Window couldn't find content container view");
- }
frameworks/base/core/java/android/view/Window.java 124行:
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
打开 screen.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>
四.
Activity的默认布局确定了,可以确定一下,修改xml 布局:
- diff --git a/base/core/res/res/layout/screen_simple.xml b/base/core/res/res/layout/screen_simple.xml
- index c1914e7..0b7f6e2 100644
- --- a/base/core/res/res/layout/screen_simple.xml
- +++ b/base/core/res/res/layout/screen_simple.xml
- @@ -25,7 +25,8 @@ enabled.
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true"
- - android:orientation="vertical">
- + android:orientation="vertical"
- + android:background="@android:color/holo_orange_dark">
- <ViewStub android:id="@+id/action_mode_bar_stub"
- android:inflatedId="@+id/action_mode_bar"
- android:layout="@layout/action_mode_bar"
- @@ -37,5 +38,6 @@ enabled.
- android:layout_height="match_parent"
- android:foregroundInsidePadding="false"
- android:foregroundGravity="fill_horizontal|top"
- - android:foreground="?android:attr/windowContentOverlay" />
- + android:foreground="?android:attr/windowContentOverlay"
- + android:background="@android:color/holo_green_dark"/>
- </LinearLayout>
homeshell.png
进入HelloWorld,没有任何变化。分析generateLayout的时候已经看到会根据窗口的属性选择不同的资源文件。桌面和一般的Activity使用了不同的资源配置。
修改screen_action_bar.xml
点击(此处)折叠或打开
- diff --git a/base/core/res/res/layout/screen_action_bar.xml b/base/core/res/res/layout/screen_action_bar.xml
- index f0b2313..62b34f6 100644
- --- a/base/core/res/res/layout/screen_action_bar.xml
- +++ b/base/core/res/res/layout/screen_action_bar.xml
- @@ -23,33 +23,39 @@ This is an optimized layout for a screen with the Action Bar enabled.
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:fitsSystemWindows="true"
- - android:splitMotionEvents="false">
- + android:splitMotionEvents="false"
- + android:background="@android:color/holo_red_dark">
- <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- - style="?android:attr/actionBarStyle">
- + style="?android:attr/actionBarStyle"
- + android:background="@android:color/holo_green_dark">
- <com.android.internal.widget.ActionBarView
- android:id="@+id/action_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- - style="?android:attr/actionBarStyle" />
- + style="?android:attr/actionBarStyle"
- + android:background="@android:color/holo_green_light"/>
- <com.android.internal.widget.ActionBarContextView
- android:id="@+id/action_context_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- - style="?android:attr/actionModeStyle" />
- + style="?android:attr/actionModeStyle"
- + android:background="@android:color/white"/>
- </com.android.internal.widget.ActionBarContainer>
- <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" />
- + android:foreground="?android:attr/windowContentOverlay"
- + android:background="@android:color/holo_orange_light"/>
- <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="?android:attr/actionBarSplitStyle"
- android:visibility="gone"
- - android:gravity="center"/>
- + android:gravity="center"
- + android:background="@android:color/holo_blue_light"/>
- </LinearLayout>
activity.png
从图中可以看到根布局是一个FrameLayout布局,就是mDecorView.DecorView extend FrameLayout。 被选中的区域为FrameLayout,就是mcontentParent,mcontentParent中有一个RelativeLayout,是我们setContentView 的R.layout.activity_main 布局文件。
相关热门文章
给主人留下些什么吧!~~
评论热议