有兴趣自己看Android源码的同学可以前往:
http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android/
本博客分析的Android版本为4.4
上一篇博客传送门:一个Activity的显示过程总结(一)
上次我们追踪源码分析到了android.app.Activity的attach方法中,接下来我们来看看下一个关键的callActivityOnCreate方法:
callActivityOnCreate
(android.app.Instrumentation)
1 | public void callActivityOnCreate(Activity activity, Bundle icicle) { |
调用了Activity的performCreate方法:
(android.app.Activity)
1 | final void performCreate(Bundle icicle) { |
调用了我们熟悉的Activity生命周期里的onCreate,在onCreate我们最熟悉的对界面初始化的函数绝对非setContentView莫属了,接下来我们一起看一下setContentView:
(android.app.Activity)
1 | public void setContentView(int layoutResID) { |
getWindow方法返回了什么?
(android.app.Activity)
1 | public Window getWindow() { |
原来setContentView方法把工作委托给了mWindow的setContentView方法,从上一篇博客我们得知mWindow的实际类型是PhoneWindow,下面来看看PhoneWindow的setContentView方法:
(com.android.internal.policy.impl.PhoneWindow)
1 | public void setContentView(int layoutResID) { |
在这个方法里有两个关键点:
- 第3行的installDecor:第一次调用setContentView时初始化顶层的DecorView
- 第7行的inflate:把我们传入setContentView inflate并置入mContentParent中
先来分析installDecor
installDecor
首先我们先来了解一下什么是DecorView:DecorView是PhoneWindow的一个内部类,继承自FrameLayout:
(com.android.internal.policy.impl.PhoneWindow)
1 | private final class DecorView extends FrameLayout implements RootViewSurfaceTaker { |
DecorView是一个非常重要的ViewGroup容器,因为它是我们Activity的第一个View,是Activity最顶层的ViewGroup。DecorView的设计使用了装饰器模式,我们setContentView设置的View其实只是DecorView的子View,DecorView通过包装在我们设置的View的外部,为我们的Activity提供了ActionBar、标题栏等控件。也即我们的Activity的UI层级可以这样表示:
接下来一起来看看installDecor方法:
(com.android.internal.policy.impl.PhoneWindow)
1 | private void installDecor() { |
首先我们看到第3行的generateDecor方法,这个方法创建了一个DecorView对象并赋给了mDecor。然后我们再看到第7行,这里有一个关键的generateLayout方法,设置了非常关键的mContentParent变量:
(com.android.internal.policy.impl.PhoneWindow)
1 | public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content; |
在该方法的第9行,使用了findViewById方法返回了我们需要的contentParent,id为第一行所示的android.R.id.content,该方法定义在Window基类中:
(android.view.Window)
1 | public View findViewById(int id) { |
其实就是返回DecorView中的id为android.R.id.content的ViewGroup(其实是一个FrameLayout)
inflate
接下来让我们回到setContentView中第7行的inflate方法,调用该方法时我们传入了我们设置layout的id和id为android.R.id.content的FrameLayout。由于inflate是个比较常见的方法,这里就不深入分析了,该方法执行的结果是:我们inflate了我们设置的layout,并把它加入了id为android.R.id.content的FrameLayout中,此时Activity的UI变为:
万万没想到原来Activity的界面是如此复杂的啊~有兴趣的朋友还可以使用SDK的tools目录下的hierarchyviewer工具打开一个Activity来查看一下是不是这样。
到这里Activity的onCreate方法的分析就结束了,先让我们看一看我们的分析路线:
handleResumeActivity
看来是时候回到ActivityThread类中,解决遗留下来的handleResumeActivity方法了:
(android.app.ActivityThread)
1 | final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, |
第6行的方法调用与Activity的onResume生命周期有关,但这次我们的重点不在这里,我们一起来看看第22行的wm(即WindowManagerImpl)的addView方法:
(android.view.WindowManagerImpl)
1 | private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); |
工作被委托给了WindowManagerGlobal(由创建方式可以猜测其使用了单件设计模式),我们一起进入WindowManagerGlobal看看:
(android.view.WindowManagerGlobal)
1 | public void addView(View view, ViewGroup.LayoutParams params, |
到这里,我们UI绘制的主角终于登场了——ViewRoot
这个方法里有两个关键点:
- 第11行ViewRoot的创建
- 第18行的setView方法
由篇幅问题,剩下的内容我们就放到下篇博客在分析了,最后再以我们的分析路线来结束本篇博客吧: