前言:本篇文章通过对APP启动过程(从点击图标—>Activity可见)的分析,来搞懂这一过程遇到的几个重要的知识点,以解心中的疑惑,同时通过对整个过程的分析,让孤立的知识点串联起来,有个更好的理解和掌握。
程序入口——ActivityThread.main()
Android程序的入口是ActivityThread类中的main()方法,就是当我们点击一个APP图标时,系统最开始执行的地方。以后当被人问到这个问题时,就不要回答“Activity的onCreate()方法”了。
执行的操作
1、调用prepareMainLooper()在主线程中创建一个消息队列。
2、创建ActivityThread对象。
3、创建Handler对象。
4、创建ApplicationThread对象
过程讲解
1、ActivityThread:每个应用程序都对应着一个ActivityThread实例,其中的main()方法是程序的入口,通过一系列的初始化操作,它最终的操作是通过调用ActivityThread.handleMessage()方法接收系统传来的消息,创建Activity。
Q:消息是由谁传递过来的?请看2.
2、ApplicationThread:每个应用程序对应着一个ApplicationThread对象,它是一个Binder对象,Binder是用来进行IPC(进程间的通信)操作的。所以它的作用是接收AMS传来的远程消息,例如AMS发送star某个Activity,然后ApplicationThread再通过Handler(线程间的通信)传递给ActivityThread,ActivityThread调用handleMessage()方法来处理这个消息,进行创建Activity的操作。由此可见,ApplicationThread是ActivityThread与AMS之间信息传递的桥梁。
Q:AMS又是啥?请看3.
3、AMS(ActivityManagerService):AMS是Android中的一个核心服务,主要负责系统中四大组建(有的文章说不包括BroadcastReceiver)的启动、切换、调度等工作。所以当我们点击打开一个APP时,AMS会向ApplicationThread发送请求开启一个Activity,然后由ApplicationThread传递给ActivityThread来进行具体操作,上面我们已经提到。
现在我们已经知道了消息传递的大体流程,当ActivityThread收到AMS传来的启动一个Activity的消息后,就会调用handleMessage()方法创建指定的Activity,具体如何做的呢?
从代码可以看出,它调用了handleLaunchActivity()方法,那我们进入看看。
该方法又调用了performLaunchActivity()方法来返回一个Activity,想必Activity应该就是在这个函数中创建完成的了。此方法执行后,又调用了handleResumeActivity()方法,我们先看performLaunchActivity()做了什么。
performLaunchActivity()
performLaunchActivity()做了哪些事
1、从ActivityClientRecord中得到接下来要启动Activity的ComponentName信息。
2、从ActivityClientRecord中得到接下来要启动Activity的信息
通过Instrumentation.newActivity方法,利用LoadedApk的类加载器尝试创建Activity的对象。
3、通过LoadedApk.makeApplication方法尝试创建Application对象,在这个方法里会通过`Class.newInstance()方法创建Application的对象,并且它的onCreate方法也是在此时被调用的。
4、为Activity创建ContextImpl的对象,调用Activity.attach()方法。
5、调用Activity.setTheme方法,如果Activity申明时指定了theme的话。
6、调用Activity.onCreate()方法,然后是onStart()方法,如果之前有保存的状态那么还会调用onRestoreInstanceState()方法,最后调用onPostCreate()方法,至此整个launch过程算是结束了。
进入onCreate()方法
下面终于进入到onCreate()方法了,首要执行的就是setContentView(R.layout.main),这个方法的目的是设置我们在xml文件中定义的布局,我们进入这个方法看看。
该方法中调用了mWindow()的setContentView()方法,因为我们可以从代码中看出getWindow()返回的是mWindow,mWindow是Window类型的,而Window是一个抽象类,它的实现类是PhoneWindow。所以, getWindow().setContentView()方法就是调用的PhoneWindow的setContentView()方法,然后我们进入看看。
首先,判断mContentParent是否为空,为空则执行installDecor()。mContentParent是什么?从代码中的注释可以看到说“mContentParent是mDecor本身或者是mDecor的一个子元素
”,mDcor是DecorView的实例,大家可能还不明白,所以要先搞清DecorView是什么,然后我们继续往下看,看看installDecor()方法做了什么。
从代码可以看出,它调用了generateDecor()方法:
好了,可以看出,这里实例化出了一个DecorView,那DecorView是什么呢?
由代码可见,DecorView继承自FrameLayout,而FrameLayout继承自ViewGroup,所以DecorView是一个ViewGroup。其实,它是ViewTree的最顶层的一个View,它是一个FrameLayout布局,代表了整个应用的界面,由TitlView和ContentView两个子元素,而ContentView则是上面提到的mContentParent,那为什么刚才注释里说“mContentParent是mDecor本身或者是mDecor的一个子元素
”呢?我们进入installDecor()中注释的2号代码:
由以上代码可以看出:首先根据设置的主题样式来设置DecorView的风格,比如说有没有titlebar之类的,接着为DecorView添加子View,而这里的子View则是上面提到的mContentParent,如果上面设置了FEATURE_NO_ACTIONBAR,那么DecorView就只有mContentParent一个子View,这也解释了上面的疑问:mContentParent是DecorView本身或者是DecorView的一个子元素。

handleResumeActivity()
performLaunchActivity()执行完了之后,接着会执行handleResumeActivity()方法,看看源码会执行哪些操作:
该方法内部会先获得与该Activity关联的几个对象:
1、WIndow对象
2、DecorView对象
3、WindowManager对象,它的实现类是WIndowManagerImpl
接着会调用WIndowManagerImpl的addView()方法:
这里面又调用了mGlobal的addView()方法,mGlobal是WindowManagerGlobal的一个实例,我们进入该方法:
1、首先实例化一个ViewRootImpl类。
2、然后调用ViewRootImpl的setView()方法,把DecorView作为参数传进去。在这里,ViewRootImpl是WMS与DecorView之间沟通的一个桥梁。
3、在这个方法内部,会通过跨进程的方式向WMS(WindowManagerService)发起一个调用,从而将DecorView最终添加到Window上。
4、最后通过WMS调用ViewRootImpl.performTraverals方法开始View的测量、布局、绘制流程。这个下一篇再讲解。
通过前面的讲解,我们可以如此总结:
Android应用程序窗口 = Activity + PhoneWindow + DecorView
DecorView = TitleView + ContentView(layout.xml文件)
画图表示如下(每一层的大小都是一样的,是覆盖关系,这里是为了方便表示出每一层):
参考:
1、http://www.voidcn.com/blog/u012827296/article/p-4991222.html
