看的框架层相关的概念容易忘记,写个备忘录把理解的重点和遇到的疑惑记下。
Context:用Android最早接触到的一个类,使用非常非常广泛,在各个地方都要用到,像Toast、Dialog、new TextView()、getResource()之类的,经常就有个参数是Context。刚开始的时候对这个对象很疑惑,翻译过来是"上下文",不好理解。事实上,很多时候我们用到的Context,就是Activity本身。在View中get到的Context,其实就是这个View所处的Activity。Activity继承于ContextThemeWrapper,ContextThemWrapper继承于ContextWrapper,ContextWrapper继承于Context。另外,当使用Service的时候,也有一个Context,这是因为Service是继承于ContextWrapper的,这个Context就是Service本身。还有一个全局的Context:Application。通过getApplicationContext获得。
ContextImpl:虽然Activity继承于Context类,但是真正执行Context类方法的并不是Activity本身,而是ContextImpl类。该类也是继承于Context类,每个Activity内部都有一个ContextImpl对象,该对象是在Activity创建时创建的。装饰模式。
ActivityThread:一个非常非常重要的类。这个类管理着一个应用程序的生命周期,是应用程序的入口。每个应用程序对应一个ActivityThread对象,甚至于我们整个Android操作系统,也对应一个ActivityThread对象。同时,Activity、Service、Application都是在此类中创建。
Binder机制:跨进程通信机制,Android系统的核心所在。最早看到这个概念是在学习利用AIDL实现跨应用分享数据的时候,直到后来看了框架层相关的一些资料后才明白,这玩意在Android中扮演着多么重要的角色。在Android中,每启动一个应用,每打开一个Activity,都需要和Android系统做交互,确切地说,是和Android系统中的各个服务做交互,你的应用的每一步操作,都需要经过这些服务的授权于管理才能正常进行,而这些服务都处于另外一个进程中,通过Binder机制来进行交互。以startActivity为例,在这个过程中,应用程序首先将自己的这一动作通过binder机制传递给了ActivityManagerService(其实是调用了ActivityManagerService的某个方法),ActivityManagerService经过一系列操作后,同意了请求,并且在内部注册了这个要启动的Activity,然后又通过Binder机制调用了ActivtiyThread的创建Activity方法,ActivityThread这才开始实例化Activity类,然后回调这个Activity类的onCreate、onResume之类的接口。由于ActivityManagerService记录了每个启动的Activity,它就可以对整个系统所有的Activity做维护了。
AMS:ActivityManagerServcie的简称。管理所有Activity的服务,Activity的生命周期通过它来调度。
WindowManagerService:管理窗口(View)的服务,界面的绘制通过它调度,事件的触发由它传递给指定View.
Activity的attach方法:由于Activity实例是通过反射机制动态创建的,它的构造函数并真正进行初始化和赋值操作,而是在创建后通过attach方法进行初始化和必要的赋值操作。方法如下。
attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance, Configuration config)
该方法是在ActivityThread中调用的,各参数详解如下
context:ContextImpl实例,前面说过Activity对于Context接口的真正实现都转到内部ContextImpl变量实现,就是在这里赋值。在创建Activity时会同时创建一个ContextImpl实例。
aThread:每个应用都对应一个ActivityThread实例,这里的aThread就是Activity所处应用对应的ActivityThread实例。由于Activity是在ActivityThread中创建和attach的,这个参数就是this。
instr:这个类型翻译过来时“检测仪器”,比较难懂是什么意思。但是在startActivity中是通过它来向AMS发送请求的,应该是个工具类,用以应用程序和系统服务的交互,会将其赋值给Activity内部的Instrumentation变量。另外这个变量是其实是ActivityThread的私有变量,实例化ActivityThread时创建的,所以一个应用内所有的Activity都共用一个Instrumentation变量。
token:IBinder对象,这个是最难理解的一点。如果对Binder机制做过了解的就会知道,IBinder对象实际上是另外一个进程内Binder服务的引用,调用它的方法就等于调用Binder服务的方法,Android系统内的各个Service,如AMS、WindowsManagerService、NotificationSerVice、LocationService等都是这么实现的,统称为服务。但更多时候,Binder机制不用于"服务"这类复杂功能的使用,而仅仅就是为了一个简单的跨进程调用,此处的IBinder对象就是如此。前面说过,startActivity时需要到AMS进行注册,注册成功后AMS该如何通知这个应用的ActivityThread创建Activity呢?实际上,在startActivity时,传递给AMS的参数中就带了一个Binder对象:ApplicationThread。到了AMS端就成了一个IBinder对象,在Activity注册成功之后AMS会调用这个IBinder对象的scheduleLaunchActivity方法,这就相当于调用了应用程序内的ApplicationThread对象的scheduleLaunchActivity方法,该方法会发送一条消息至应用主线程的Handler,最后执行到ActivityThread的performLaunchActivity方法,在这个方法中进行Activity的创建和赋值工作。此处的token,便是在AMS端创建的一个Binder对象的引用,注意它不是AMS这个服务的引用,而是AMS为每个注册的Activity单独创建的Binder对象,类型为Token,继承于IApplicationToken.Stub,它是在创建ActivityRecord对象时同时创建的,看名字就知道ActivityRecord对应于一个Activity的记录。这个token对象有什么用呢?更多时候,它是作为查找ActivityRecord的键存在的,token/ActivityRecord作为键值对保存在AMS中。另外,在源码中这个变量的注释是:window manager token。可能还有个用途是用以和WindowManagerService通信用的,之后看到WindowManagerService相关内容后再补充。用途补充:由于AMS需要管理Activity,正常的做法是把每创建一个Activity就把它的引用传到AMS中,而使用token相当于是通过token进行管理,因为每个token对应了一个Activity,就不需要传Activity过来了。
ident:本质是AMS端调用了 System.identityHashCode(r),r为ActivityRecord对象,通过内存地址获取hash值。这个对象是干什么用的,暂时没看到,之后补充。
application:应用对应的application。这个很简单,也经常用到,Activity的getApplication方法获取的就是这个值,同样的,一个应用只有一个application对象,不同Activity内的application对象是同一个。
intent:虽然这个intent是从ActivityManagerServcie端传过来的,但是它的值应该就是startActivity时的值。注意,在AMS端进行了new Intent(r.intent)的重新实例化,并不是同一个。
info:ActivityInfo对象,由AMS传递过来,是在AndroidManifest.xml文件中描述Activity节点的内容,对于AndroidManifest文件的解析AMS服务端而不是应用这边。包含主题、载入方式之类的一系列配置内容。用处嘛,比方说主题,在设置ContentView的时候就有用了。
title:Activity标题。这是在应用端获取的,通过Activityinfo对象调用PackageManager进行获取。
parent:查了半天没弄清这玩意究竟干什么用,因为在正常的startActivity过程中,parent参数即不在AMS端赋值,也不在应用端赋值,后来全局搜索了一下发现它只在一个startActivityNow方法中进行赋值,上stackoverflow上一查,原来是早期使用TabActivity时用到的,TabActivity内部的Activity的这个变量拥有值,指向TabActivity。同时,内部Activity的启动是不经过Ams的。该技术现在已被淘汰,可以不关注这个变量的使用。
id:这个同上,也是在TabActivity中使用的,用以表面在TabActivity中该Activity的独有ID。
lastNonConfigurationInstances:这个也同上,也是TabActivity中用的,我就没查具体用途了。
config: Configuration config = new Configuration(mCompatConfiguration);通过ActivityThread的mCompatConfiguration对象进行赋值,可以认为所有一个应用内Activity的config 值是相同的。Configuration对象记录了手机的硬件配置类型,如键盘类型、是否触屏。