您的位置:首页 > 移动开发 > Android开发

【Android】Framework概述

2016-01-12 23:18 330 查看

Framework概述

从本篇博文开始,真正进入Android Framework内核之旅.

任何控制类程序都有一个入口,汇编程序的入口由处理器内部的复位(Reset)中断向量表决定;C程序的入口是main()函数,一个C程序只能有一个main()函数;java程序的入口必须是某个类的静态成员函数main().

对于依赖于操作系统的程序,客户程序除了包含一个程序入口外,还需要和相关系统服务一起运行,以完成指定的任务.比如,Win32程序需要和GUI系统服务一起实现带有可视窗口的功能;X Window程序也需要和X Window Server一起实现窗口功能.

Android程序也不例外,那么Android程序的入口在哪里?Android Framework都包含哪些必需的系统?这些系统服务是如何与Android APK程序配合的?本博文将回答这些问题.关于各组件内部具体实现过程将在后续博文中分别阐述.

Framework框架

Framework定义了客户端组件和服务端组件功能及接口.以下阐述中,”应用程序”一般是指定”.apk”程序.

框架中包含三个主要部分,分别为服务端,客户端和Linux驱动.

1.1 服务端

服务端主要包含两个重要的类,分别是WindowManagerService(WmS)和ActivityManagerService(AmS).WmS的作用是为所有的应用程序分配窗口,并管理这些窗口.包括分配窗口的大小,调节各窗口的叠放次序,隐藏或者显示窗口.AmS的作用是管理所有应用程序中的Activity.

除此之外,在服务端还包括两个消息处理类.

KeyQ类:该类为WmS的内部类,继承于KeyInputQueue类,KeyQ对象一旦创建,就立即启动一个线程,该线程会不断地读取用户的UI操作消息,比如按键,触摸屏,trackball,鼠标等,并把这些消息放到一个消息队列QueueEvent类中.

InputDispatcherThread类:该类的对象一旦创建,也会立即启动一个线程,该线程会不断地从QueueEvent中取出用户消息,并进行一定的过滤,过滤后,再将这些消息发送给当前活动的客户端程序中.

1.2 客户端

客户端主要包括以下重要类.

ActivityThread类:该类为应用程序的主线程类,所有的APK程序都有且仅有一个ActivityThread类,程序的入口为该类中的static main()函数.

Activity类:该类为APK程序的一个最小运行单元,一个APK程序中可以包含多个Activity对象,ActivityThread主类会根据用户操作选择运行哪个Activity对象.

PhoneWindow类:该类继承于Window类,同时,PhoneWindow类内部包含了一个DecorView对象.简而言之,PhoneWindow是把一个FrameLayout进行了一定的包装,并提供了一组通用的窗口操作接口.

Window类:该类提供了一组通用的窗口(Window)操作API,这里的窗口仅仅是程序层面上的,WmS所管理的窗口并不是Window类,而是一个View或者ViewGroup类,一般就是指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进行交互.

1.3 Linux驱动

Linux驱动和Framework相关的主要包含两部分,分别是SurfaceFlinger(SF)和Binder.每一个窗口都对应一个Surface,SF驱动的作用是把各个Surface显示在同一个屏幕上.

Binder驱动的作用是提供跨进程的消息传递.

APK程序的运行过程

首先,ActivityThread从main()函数中开始执行,调用prepareMainLooper()为UI线程创建一个消息队列(MessageQueue).

然后创建一个ActivityThread对象,在ActivityThread的初始化代码中会创建一个H(Handler)对象和一个ApplicationThread(Binder)对象.其中Binder负责接收远程AmS的IPC调用,接收到调用后,则通过负责接收远程AmS的IPC调用,接收到调用后,则通过Handler把消息发送到消息队列,UI主线程会异步地从消息队列中取出消息并执行相应操作,比如start,stop,pause等.

接着UI主线程调用Looper.loop()方法进入消息循环体,进入后就会不断地从消息队列中读取并处理消息.

当ActivityThread接收到AmS发送start某个Activity后,就会创建指定的Activity对象.Activity又会创建PhoneWindow类->DecorView类->创建相应的View或者ViweGroup.创建完成后,Activity需要把创建好的界面显示到屏幕上,于是调用WindowManager类,后者于是创建一个ViewRoot对象,该对象实际上创建了ViewRoot类和W类,创建ViewRoot对象后,WindowManager再调用WmS提供的远程接口完成添加一个窗口并显示到屏幕上.

接下来,用户开始在程序界面上操作.KeyQ线程不断把用户消息存储到QueueEvent队列中,InputDispatcherThread线程逐个取出消息,然后调用WmS中的相应函数处理该消息.当WmS发现该消息属于客户端某个窗口时,就会调用相应窗口的W接口.

W类是一个Binder,负责接收WmS的IPC调用,并把调用消息传递给ViewRoot,ViewRoot再把消息传递给UI主线程ActivityThread,ActivityThread解析该消息并做相应的处理.在客户端程序中,首先处理消息的是DecorView,如果DecorView不想处理某个消息,则可以将该消息传递给其内部包含的子View或者ViewGroup,如果还没有处理,则传递给PhoneWindow,最后再传递给Activity.

客户端中的线程

在多任务操作系统中,任何程序都运行在线程之中.系统首先会为客户端程序分配一个线程,然后该线程从程序的入口处开始执行.那么,请思考以下问题.

Android APK程序中都有哪些线程?

什么是UI线程?

程序中自定义Thread和UI线程的区别是什么?

首先,很明确地讲,包含Activity的客户端程序至少包含三个线程,如下图所示.每个Binder对象都对应一个线程,Activity启动后会创建一个ViewRoot.W对象,同时ActivityThread会创建一个ApplicationThread对象,这两个对象都继承于Binder,因此会启动两个线程,负责接收Linux Binder驱动发送IPC调用.最后一个主要线程也就是程序本身所在的线程,也叫做用户交互(UI)线程,因为所有的处理用户消息,以及绘制界面的工作都在该线程中完成.

为了验证这一点,可以在Eclipse中新建一个Hello Android的程序,然后以debug的方式运行,在debug窗口中会看到下图所示的界面.



自定义Thread和UI线程的区别在于,UI线程是从ActivityThread运行的,在该类中的main()方法中,已经使用Looper.prepareMainLooper()为该线程添加了Looper对象,即已经为该线程创建了消息队列(MessageQueue),因此,程序员才可以在Activity中定义Handler对象(因为声明Handler对象时,所在的线程必须已经创建了MessageQueue).而普通的自定义Thread是一个裸线程,因此,不能直接在Thread中定义Handler对象,从使用场景的角度讲,即不能直接给Thread对象发消息,但是却可以给UI线程发消息.

几个常见问题

在过去的实践中,经常有同学问到以下几个问题,故特意将此作为一节.

4.1 Activity之间如何传递消息(数据)

首先,提出这个问题的原因是,程序员需要在不同的Activity之间传递数据,然而,这个问题本身就有问题.所谓”传递消息”一般是指多个线程之间,而Activity本身并不是线程,ActivityThread才是一个线程,即UI线程.同一个程序中的多个Activity都由ActivityThread进行调用,Activity本身只是一个java类而已,就像Rect,Trigle类一样,如果有人问”Rect类和Trigle类之间如何传递消息”,你会不会觉得有点奇怪?

事实上,如果要在两个类中传递数据,方法可以有很多.

方法一:可以先实例化某个类,获得该类的引用,当其他类需要该对象的内部数据时,要吧直接通过该引用去访问该类的内部数据.

方法二:对于A,B两个类之间,可以先实例化一个第三方类C,然后两个类都可以把需要传递的数据存入C中,或从C中取出.

这些方法理论上都可以用在Activity类之间传递数据.然而,与普通类传递数据有所不同,普通类的实例化都是程序员显式完成的,而Activity类的实例化却是由Framework完成的,程序员只能使用startActivity()方法来告诉Framework去运行哪个Activity,这就意味着程序员不能得到Activity对象的引用,那么就不能直接访问该对象的内部数据.解决的办法是使用Activity.getApplication()函数,该函数能够返回一个Application对象,该Application对象在该程序中是唯一的,同一程序中的不同Activity调用该函数所返回的Application对象是相同的,该对象的名称可以在AndroidManifest.xml中指定.一旦获取了该Applicatin对象,就可以借助该对象,在不同的Activity之间传递数据.

除此之外,Framework本身也提供了标准的Activity之间传递数据的方法,即Intent类.该类作为startActivit()的参数,仅用于在启动Activity时传递给目标Activity,同时,如果调用startActivityForResult(),目标Activity在结束后,也会返回一个Intent对象给原Activity.

另外,从设计理念的角度来看,Android认为,两个Activity如果要共享数据,可以通过Preference Storage或者文件,数据库进行,同时,在一般情况下,设备上只会有一个Activity在支行,因此,多个Activity之间传递数据也不是必需的.如果某个Activity需要在停止后还能处理某些数据,那么,该Activity似乎更应该被设计为一个后台的Thread或者一个Service,无论是Thread还是Service都很容易获得其引用.

4.2 窗口相关的概念

在源码和本文中,会经常提到以下概念,窗口,Window类,ViewRoot类以及W类,本节简单介绍这些概念的联系和区别.

首先澄清几个概念.

窗口(Window):这是一个纯语义的说法,即程序员所看到的屏幕上的某个独立的界面,比如一个带有Title Bar的Activtiy界面,一个对话框,一个Menu菜单等,这些都称之为窗口.本书中所说的窗口管理一般也都泛指所有这些窗口,在Android的英文相关文件中则直接使用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类.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android