想过没?Android程序的入口在哪里?Android Framework都包含哪些必需的系统服务?这些系统
服务时怎样与Android APK程序配合的?
Framework定义了客户端组件和服务端组件功能及接口。在Android中,"应用程序"一般是指".apk"程序。
框架中包含三个主要部分,分别为服务端、客户端和Linux驱动。
服务端主要包含两个重要类,分别是WindowManagerService(WmS)和ActivityManagerService(AmS)。
WmS的作用是为所用应用程序分配窗口,并且管理这些窗口。包括分配窗口的大小,调节各窗口的叠放次序,隐
藏或者显示窗口。AmS的作用是管理所用应用程序中的Activity。
除以上(WmS和AmS)以外,服务端还包括两个消息处理类:
KeyQ类:WmS的内部类,继承于KeyInputQueue类,KeyQ对象一旦创建了,就立即启动一个线程,该
线程会不断地读取用户的UI操作消息,比如按键、触摸屏、trackball、鼠标等,并把这些消息放在消息队列
QueueEvent类中。
InputDispatcherThread类:该类的对象一旦创建,也会立即启动一个线程,该线程会不断地从QueueEvent
中取出用户的消息,并进行一定的过滤,过滤后,再将这些消息发送给当前活动的客户端程序中。
客户端主要包含几个重要类:
ActivityThread类:应用程序的主线程类,所有的APK程序都有且仅有一个ActivityThread类,程
序的入口就是ActivityThread类中的static main()函数。
Activity类:APK程序的最小运行单元。一个APK程序中可以包含多个Activity对象,ActivityThread
主类会根据用户操作选择运行哪个Activity对象。
PhoneWindow类:该类继承于Window类,同时,PhoneWindow类内部包含了一个DecorView对象。
简而言之,PhoneWindow是把一个FrameLayout进行了一定的包装,并提供了一
组通用的的窗口操作接口。
Window类:该类提供了一组通用的窗口(Window)操作API,这里的窗口仅仅是程序层面上的,Wms
所管理的窗口并不是Window类,而是一个View类或者ViewGrop类,一般就是指DecorView
类,即一个DecorView就是Wms所管理的一个窗口。Window是一个abstract类型。
DecorView类:该类是FrameLayout的子类。并且是PhoneWindow中的一个内部类。Decor的英文是
Decoration,即"修饰"的意思,DecorView就是对普通的FrameLayout进行了一定的
修饰,不如添加一个通用的Title bar,并响应特定的按键消息等。
ViewRoot类:Wms管理客户端窗口时,需要通知客户端进行某种操作,这些都是通过异步消息完成的,
实现方式就是Handler,ViewRoot就是继承于Handler,其作用主要是接收Wms的通知。
W类:该类继承于Binder,并且是ViewRoot的一个内部类。
WindowManager类:客户端要申请创建一个窗口,而具体创建窗口的任务是由Wms完成的
WindowManager类就像是一个部门经理,谁有什么需求就告诉它,由它和
Wms进行交互,客户端不能直接和Wms交互。
Linux驱动和Framework相关的主要包含两个部分。分别是SurfaceFlingger(SF)和Binder。每一个
窗口都对应一个Surface,SF驱动的作用是把各个Surface显示同一个屏幕上。
Binder驱动的作用是提供跨线程的消息传递。
1.首先,ActivityThread从main()函数中开始进行,调用prepareMainLooper()为UI线程创建一个
消息队列(MessageQueue)。
2.然后创建一个ActivityThread对象,在ActivityThread的初始化代码中会创建一个H(Handler)对
象和一个ApplicationThread(Binder)对象。其中Binder负责接收远程Ams的IPC调用,接收到调用
后,则通过Handler把消息发送到消息队列,UI主线程会异步地从消息队列中取出消息并执行相应操
作,比如start()、stop()、pause()等。
3.接着UI主线程调用Looper.loop()方法进入消息循环体,进入后就会不断从消息队列中读取并处理消息。
4.当ActivityThread接收到Ams发送start某个Activity后,就会创建指定的Activity对象。Activity又会
创建PhoneWindow类->DecorView类->创建相应的View或者ViewGroup。创建完成后,Activity
需要把创建好的界面显示到屏幕上,于是调用WindowManager类,WindowManager于是创建一个ViewRoot对
象,该对象实际上创建了ViewRoot 类和W 类,创建ViewRoot对象后,WindowManager再调用WmS
提供的远程接口完成添加一个窗口并显示到屏幕上。
5.接下来,用户开始在程序界面上操作。KeyQ线程不断把用户消息存储到QueueEvent队列中
InputDispatcherThread线程逐个取出消息,然后调用WmS中的相应函数处理该消息。当WmS发现该消
息属于客户端某个窗口时,就会调用相应窗口的W 接口。
6. W类是一个Binder,负责接收Wms的IPC调用,并把调用消息传递给ViewRoot,ViewRoot再把消息传
递给UI主线程ActivityThread,ActivityThread解析该消息并做相应的处理。在客户端程序中,首先处理消
息的是DecorView,如果是DecorView不想处理某个消息,则可以将该消息传递给其内部包含在子View或
则ViewGroup,如果还没处理,则传递给PhoneWindow,最后再传递给Activity。
1、2、3 图示:
4 图示:
5 图示:
6 图示:
很明确的说!包含有Activity的客户端程序至少包含三个线程。
每一个Binder对象都对应一个线程,Activity启动后会创建一个ViewRoot.W 对象,同时ActivityThread
会创建一个ApplicationThread对象,这两个对象都是继承于Binder,因此会启动两个线程,负责接收Linux
Binder驱动发送IPC调用。最后一个主要线程也就是程序本身所在的线程,也叫做用户交互(UI)线程,因为
所有的处理用户消息,以及绘制界面的工作都在该线程中完成的。
自定义Thread和UI线程的区别在于:UI线程是从ActivityThread运行的,在该类中的main()方法中,已经使用
Looper.prepareMainLooper()为该线程添加了Looper对象,即已经为该线程创建了消息队列(MessageQueue)
因此我们才可以直接在Activity中定义Handler对象(因为声明Handler对象时,所在的线程必须已经创建了
MessageQueue)。而普通的自定义Thread是一个裸线程,因此,不能直接在Thread中定义Handler对象,从使
用场景的角度来讲,即不能直接给Thread对象发消息,但是却可以给UI线程发消息。
有时候需要在不同的Activity之间传递数据,然而,这个问题本身就有问题。所谓“传递消息” 一般是指多个
线程之间,而Activity.本身并不是线程,ActivityThread才是一个线程,即UI线程。同一个程序中的多个Activity
都由ActivityThread进行调用, Activity本身只是一个Java类而已。
事实上,如果要在两个类中传递数据, 方法可以有很多。
方法一:可以先实例化某个类,获得该类的引用,当其他类需要该对象的内部数据时,可以直接通
过该引用去访问该类的内部数据。
方法二:对于A、B 两个类之间,可以先实例化一个第三方类C,然后两个类都可以把需要传递的
数据存入C 中,或从C 中取出。
这些方法理论上都可以用在Activity类之间传递数据。然而,与普通类传递数据有所不同,普通类
的实例化都是程序员显式完成的,而Activity类的实例化却是由Framework完成的,程序员只能使用
startActivityO方法来告诉Framework去运行哪个Activity,这就意味着程序员不能得到Acitivity对象的
引用,那么就不能直接访问该对象的内部数据。解决的办法是使用Activity.getApplicationO函数,该函
数能够返回一个Application对象,该Application对象在该程序中是唯一的,同一程序中的不同Activity
调用该函数所返回的Application对象是相同的,该对象的名称可以在AndroidManifest.xml中指定。一
旦获取了该Application对象,就可以借助该对象,在不同的Activity之间传递数据。
除此之外,Framework本身也提供了标准的Activity之间传递数据的方法,即Intent类。该类作为
startActivity()的参数, 仅用于在启动Activity时传递给目标Activity, 同时, 如果调用
startActivityForResult(), 目标 Activity 在结束后, 也会返回一个 Intent 对象给原 Activity。
从设计理念的角度来看,Android认为,两个Activity如果要共享数据,可以通过Preference
Storage或者文件、数据库进行,同时,在一般情况下,设备上只会有一个Activity在运行,因此,多
个Activity之间传递数据也不是必需的。如果某个Activity需要在停止后还能处理某些数据,那么,该
Activity似乎更应该被设计为一个后台的Thread或者一个Service,无论是Thread还是Service都很容易
获得其引用。
窗口(Window):从WmS的角度来讲,窗口是接收用户消息的最小单元,WmS内部用特定的类表示一个
窗口,以实现对窗口的管理。WmS接收到用户消息后,首先要判断这个消息属于哪个窗口,然后通
过IPC调用把这个消息传递给客户端的ViewRoot类。
Window类:该类在android.view包中,是一个abstract类,该类是对包含有可视界面的窗口的一种包装。
所谓的可视界面就是指各种View或者ViewGroup,一般可以通过res/layout目录下的xml文件描述。
ViewRoot类:该类在android.view包中,客户端申请创建窗口时需要一个客户端代理,用以和WmS进行
交互,这个就是ViewRoot的功能,每个客户端的窗口都会对应一个ViewRoot类。
W 类:该类是ViewRoot类的一个内部类,继承于Binder,用于向WmS提供一个IPC接口,从而让WmS控制
窗口客户端的行为。
描述一个窗口之所以使用这么多类的原因在于,窗口的概念存在于客户端和服务端(WmS)之中,客户
端所理解的窗口和服务端理解的窗口是不同的,因此,在客户端和服务端会用不同的类来描述窗口。同时,无
论是在客户端还是服务端,对窗口都有不同层面的抽象,比如在客户端,用户能看到的窗口一般是View或者
ViewGroup组成的窗口,而与Activity对应的窗口却是一个DecorView类,而具备常规Phone操作接口的窗口
却又是一个PhoneWindow类。