android的窗口创建过程

待补充!

一个窗口本质上是一个view,而Window类只是一个应用窗口的抽象。

①    启动activity的代码本质,是一个创建activity的过程,是由ActivityThread完成的。其代码如下:

2109        Activity activity = null;
2110        try {
2111            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
2112            activity = mInstrumentation.newActivity(
2113                    cl, component.getClassName(), r.intent);
2114            StrictMode.incrementExpectedActivityCount(activity.getClass());
2115            r.intent.setExtrasClassLoader(cl);
2116            if (r.state != null) {
2117                r.state.setClassLoader(cl);
2118            }
2119        } catch (Exception e) {
2120            if (!mInstrumentation.onException(activity, e)) {
2121                throw new RuntimeException(
2122                    "Unable to instantiate activity " + component
2123                    + ": " + e.toString(), e);
2124            }
2125        }

使用ClassLoader从程序文件中装载指定的activity对应的class文件。

②    构造好指定的activity对象后,接着调用activity的attach方法,代码如下:

2144                activity.attach(appContext, this, getInstrumentation(), r.token,
2145                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
2146                        r.embeddedID, r.lastNonConfigurationInstances, config);

attach方法的第一个作用是为刚刚构造好的activity设置内部变量,不是现在的重点,忽略。第二个作用就是为该activity创建Window对象,代码如下:

5180    final void attach(Context context, ActivityThread aThread,
5181            Instrumentation instr, IBinder token, int ident,
5182            Application application, Intent intent, ActivityInfo info,
5183            CharSequence title, Activity parent, String id,
5184            NonConfigurationInstances lastNonConfigurationInstances,
5185            Configuration config) {
5186        attachBaseContext(context);
5187
5188        mFragments.attachActivity(this, mContainer, null);
5189
5190        mWindow = PolicyManager.makeNewWindow(this);
5191        mWindow.setCallback(this);

Window对象是由PolicyManager的静态方法makeNewWindow()完成的。PolicyManager会根据不同的类型来创建不同的产品类型窗口(可以看看策略设计模式),这里其代码只是创建了一个PhoneWindow对象而已。当前的Framework中仅仅只有两种Window的具体实现:PhoneWindow—手机,MidWindow—便携上网设备,这里也可以看出android设计的初衷。Window对象创建完成之后,将其值赋值给Activity的内部变量mWindow,并设置Window的Callback回调接口为当前的activity对象(显然activity需要实现这个接口),这就是为什么用户消息能够传递到Activity中的原因。

③    创建好Window对象之后,需要给Window对象的mWindowManager赋值。这个也不是此文重点,但是仍然说明一下,赋值代码如下:

mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
     mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();

Window的setWindowManager方法里面:

mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

createLocalWindowManager方法的实现:

public WindowManagerImpl createPresentationWindowManager(Display display) {
      return new WindowManagerImpl(display, mParentWindow);
}

所以最终,Window是创建了一个WindowManagerImpl对象,WindowManager是一个接口。

④    配置好Activity和Window之后,接下来需要给窗口添加真正的显示元素View或者ViewGroup了。ActivityThead启动activity的一系列流程,都在其performLaunchActivity()中。在attach()之后便会执行到callActivityOnCreate()方法,这个方法会触发Activity的onCreate方法。而在onCreate方法里面,我们会setContentView(),看看其代码:

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

这个方法调用Window对象的setContentView方法,接下来我们要分析的就是看Window是如何把layout.xml作为Window界面的显示元素。

PhoneWindow的setContentView()方法如下:

284     public void setContentView(int layoutResID) {
285         if (mContentParent == null) {
286             installDecor();
287         } else {
288             mContentParent.removeAllViews();
289         }
290         mLayoutInflater.inflate(layoutResID, mContentParent);
291         final Callback cb = getCallback();
292         if (cb != null && !isDestroyed()) {
293             cb.onContentChanged();
294         }
295     }

代码首先调用installDecor()方法为Window类安装一个窗口修饰,所谓的窗口修饰就是界面上常见的标题栏,我们写的layout.xml将会被包含到窗口修饰中,称为窗口内容。窗口修饰及窗口内容关系如下图:

Framework中定义了多种窗口修饰,installDecor()代码如下:

3075    private void installDecor() {
3076        if (mDecor == null) {
3077            mDecor = generateDecor();
3078            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
3079            mDecor.setIsRootNamespace(true);
3080            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
3081                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
3082            }
3083        }
3084        if (mContentParent == null) {
3085            mContentParent = generateLayout(mDecor);

该代码主要完成了三个工作:

  1. generateDecor()生成一个DecorView对象,赋值给mDecor,mDecor并不是窗口修饰,而是窗口修饰的唯一子视图。
  2. 根据用户指定的参数来选择不同的窗口修饰,然后将窗口修饰作为mDecor的子窗口,这是在generateLayout()中调用mDecor.addView()完成的。
  3. 给mContentParent变量赋值,generateLayout返回值的由来:
...ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;

那么这个ID_ANDROID_CONTENT是什么呢?

public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

就是找一个id=content的布局,为什么返回这个以及返回这个做什么,请看下面!

其中第二个工作非常重要,根据用户指定的参数来选择不用的窗口修饰实际上就是指定activity的样式。

generateLayout()中调用mDecor.addView()的view是怎么来的?看如下代码:

int layoutResource;...
int features = getLocalFeatures();//这里就是我们在onCreate里写requestFeature()起作用的原因。
2967        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
2968            if (mIsFloating) {
2969                TypedValue res = new TypedValue();
2970                getContext().getTheme().resolveAttribute(
2971                        com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);
2972                layoutResource = res.resourceId;
2973            } else {
2974                layoutResource = com.android.internal.R.layout.screen_title_icons;
2975            }
2976            // XXX Remove this once action bar supports these features.
2977            removeFeature(FEATURE_ACTION_BAR);
2978            // System.out.println("Title Icons!");
2979        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
2980                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
2983            layoutResource = com.android.internal.R.layout.screen_progress;
2985        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
2988            if (mIsFloating) {
2989                TypedValue res = new TypedValue();
2990                getContext().getTheme().resolveAttribute(
2991                        com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true);
2992                layoutResource = res.resourceId;
2993            } else {
2994                layoutResource = com.android.internal.R.layout.screen_custom_title;
2995            }
2997            removeFeature(FEATURE_ACTION_BAR);
2998        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
3001            if (mIsFloating) {
3002                TypedValue res = new TypedValue();
3003                getContext().getTheme().resolveAttribute(
3004                        com.android.internal.R.attr.dialogTitleDecorLayout, res, true);
3005                layoutResource = res.resourceId;
3006            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
3007                layoutResource = com.android.internal.R.layout.screen_action_bar;
3008            } else {
3009                layoutResource = com.android.internal.R.layout.screen_title;
3010            }
3012        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
3013            layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;
3014        } else {
3016            layoutResource = com.android.internal.R.layout.screen_simple;
3018        }

上面的代码就是,根据不同的修饰来加载不同的布局:

3022        View in = mLayoutInflater.inflate(layoutResource, null);
3023        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
3024
3025        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

加载完布局之后,将布局添加到DecorVeiw中,并将布局中id=content的布局返回出去。

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

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

如此,回到setContentView方法,就是将id=content的布局返回了,并且作为我们写的layout.xml的父布局,窗口的视图设置就完成了。

时间: 2024-08-24 17:47:47

android的窗口创建过程的相关文章

VC++编程之第三课笔记——MFC窗口创建过程以及窗口类的封装

第三课 MFC窗口创建过程以及窗口类的封装 MFC的每一个类都是以C开头的,表明这是一个Class. 工程包含(单文档) 创建工程名为aaa的工程(单文档)时,在类视图中可看见五个类: CAboutDlg CMainFrame CAaaApp CAaaDoc CAaaView 其中: 类CAboutDlg继承自CDialog类,对话框的类 类CMainFrame继承自CFrameWnd类,创建整个程序的框架窗口 类CAaaApp继承自CWinApp类,创建唯一的应用程序对象 类CAaaDoc继承

Android4.4 Framework分析——Activity窗口的创建过程(一)

学习android的窗口模块一周多了,感觉自己对这个模块的理解还是比较模糊,先把get的知识点记录一下. 下图是学习过程记录的activity窗口启动过程序列图,没有或者没办法完整的描绘出来,整个过程比较复杂: 整个学习过程中是参照老罗的android之旅博客和<深入理解android内核设计思想>一书来辅助的,非常感谢前辈. Activity的整体启动过程可查看Android4.4 framework分析--Launcher中启动应用程序(startActivity)的过程的序列图,本文关注

Android Context创建过程

    特定的资源或者类构成了Android应用程序的运行上下文环境 PackageManager, ClassLoader, Assert等等 Android应用程序窗口的运行上下文环境是通过ContextImpl类来描述的,即每一个Activity组件都关联有一个ContextImpl对象.ContextImpl类继承了Context类,它与Activity组件的关系如图 这个类图在设计模式里面就可以称为装饰模式 Activity组件以后就可以通过这个ContextImpl对象来执行一些具体

MFC应用程序创建窗口的过程 good

MFC应用程序中处理消息的顺序 1.AfxWndProc()      该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc 2.AfxCallWndProc()  该函数负责保存消息(保存的内容主要是消息标识符和消息参数)供应用程序以后使用,然后调用WindowProc()函数 3.WindowProc()      该函数负责发送消息到OnWndMsg()函数,如果未被处理,则调用DefWindowProc()函数 4.OnWndMsg()        该函

Android Window 三 创建应用窗口

创建应用窗口 一.创建Activity 1. 应用窗口必须对应Activity,AMS通知客户端ActivityThread启动Activity .反射创建Activity对象 二.创建Window 2. activity.attach()方法设置内部变量. 3. activity.attach()方法创建Window对象.PolicyManager.makeNewWindow()创建(通过com.android.internal.policy.impl.Policy配置)创建PhoneWond

在Android Studio中创建(或添加)第一个Hello World应用程序

下面我们将使用Android Studio创建第第一个简单的Hello World应用程序. 1.打开Android Studio,加载画面如下图所示: 2.选择"Start a new Android Studio project",如下图所示: 3.输入应用程序名.选择项目路径,然后点击"Next",如下图所示: 4.选择最小版本的SDK,然后点击"Next",如下图所示: 5.选择"Blank Activity",然后选

浅析 Android 的窗口

一.窗口的概念 在开发过程中,我们经常会遇到,各种跟窗口相关的类,或者方法.但是,在 Android 的框架设计中,到底什么是窗口?窗口跟 Android Framework 中的 Window 类又是什么关系?以手机QQ 的主界面为例,如下图所示,上面的状态栏是一个窗口,手机QQ 的主界面自然是一个窗口,而弹出的 PopupWindow 也是一个窗口,我们经常使用的 Toast 也是一个窗口.像 Dialog,ContextMenu,以及 OptionMenu 等等这些都是窗口.这些窗口跟 W

浅析Android的窗口

一.窗口的概念 在开发过程中,我们经常会遇到,各种跟窗口相关的类,或者方法.但是,在 Android 的框架设计中,到底什么是窗口?窗口跟 Android Framework 中的 Window 类又是什么关系?以手Q 的主界面为例,如下图所示,上面的状态栏是一个窗口,手Q 的主界面自然是一个窗口,而弹出的 PopupWindow 也是一个窗口,我们经常使用的 Toast 也是一个窗口.像 Dialog,ContextMenu,以及 OptionMenu 等等这些都是窗口.这些窗口跟 Windo

Activtiy完全解析(一、Activity的创建过程)

??在Android开发过程中,我们几乎每天都在跟Activity打交道.我们循规蹈矩的调用startActivity()方法便可以打开一个新的界面,但是这个界面是怎样从无到有我们却不是很清楚,也有很多人根本就没有想过.我们写的layout布局通过setContentView()方法是怎样加载到activity中,然后又是怎样显示到界面上的?这一系列的问题相信大多数人都不清楚. ??也许是因为我们平时的开发过程根本不需要了解这些,但是如果深入了解后,对我们还是很有帮助的.接下来我们用3篇文章去分