概述
在android studio创建一个新项目的时候,或者初学者在刚踏入android开发的时候,都会在首先创建一个MainActivity。根据一般的理解,Activity的就相当于一个界面的入口,所有和界面相关的代码都可以在activity中编写。但是随着经验的增加和项目的深入,不禁要问activity的原理是什么?为什么我们在onCreate()中设置contentView,然后显式或者隐式启动这个activity,就能够在界面上显示,就能够响应用户的点击事件了呢?
其实Activity并不直接是一个能够显示页面的类。在启动时,Activity先通过Binder机制向ActivityServiceManager注册,然后Service通过调用ApplicationThread中的方法向主线程的Handler发送消息,Handler调用ActivityThread中的方法处理activity的创建过程。创建Activity时新建一个DecorView对象,而DecorView正是这个activity界面所有view的根对象。随后,将用户定义的ContentView添加到DecorView中。到这里Activity应该已经创建完成了,但差一个很重要的过程,还没有显示出来!创建以后会继续调用Resume方法,这里会将DecorView注册到WindowManagerService中,然后界面就能接收外界的输入消息了并且显示了。到这里,Activity的视图才最终被用户所看到。页面显示后,系统会将点击事件传递给Activity,用户就可以与Activity视图进行交互了。
那么如何开始我们的启动之旅呢。首先,我们先了解下android系统的架构,相信很多人在刚开始学的时候就已经看过这个框架。我们先看一下系统的framework层和我们应用之间的关系,先有一个整体的概念。其次,应用启动的时候,都会启动一个dalvik虚拟机,然后运行应用的主线程,然后再去加载我们的activity,我们就一步一步去跟踪Activity'的启动流程。所以这一篇先介绍framework层,再介绍如何看源码。具体的activity实现流程等到以后的博客中再去分析。
应用与framework层的关系
android框架
相信大家都对这张框架图不陌生,从整体框架来看,主要分为Linux内核层,库和运行时层,framework层和应用层。以本人的能力,当然无法讲解整个体系,只是说一下framework层和应用的联系的一点理解。
android framework层
我们观察framework层的各个子模块,会发现一个共同点,他们都是以manager、service、provider结尾的。这让我们想到了framework层的作用大概是提供服务或者管理用的层。因为系统会通过各种manager管理我们的应用,也会向我们提供各种服务,所以我们猜测,那么我们在创建应用或者创建activity时,必然会和各种framework层的模块打交道。
系统service的启动
在Android启动过程中,系统会启动各种framework层的服务。所以来看下SystemServer这个类。从名字可以看出它提供了系统运行时所需要各种java编写的“系统服务”。
public static void main(String[] args) {
new SystemServer().run();
}
public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
}
private void run() {
...
// Start services.
try {
//启动引导服务
startBootstrapServices();
//启动核心服务
startCoreServices();
//启动另外一些服务
startOtherServices();
} catch (Throwable ex) {
throw ex;
}
...
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在启动引导和核心服务的方法中会启动如下一些service和manager
private PowerManagerService mPowerManagerService;
private ActivityManagerService mActivityManagerService;
private DisplayManagerService mDisplayManagerService;
private PackageManagerService mPackageManagerService;
private PackageManager mPackageManager;
在启动另外的服务时会启动如下一些service(没有列全)
NetworkManagementService networkManagement = null;
ConnectivityService connectivity = null;
WindowManagerService wm = null;
InputManagerService inputManager = null;
TelephonyRegistry telephonyRegistry = null;
AudioService audioService = null;
CameraService cameraService = null;
系统service与应用如何交互
看到这些名字,我们都会感觉很熟悉,因为在写应用的时候,经常或通过java context.getSystemService(Context.ACTIVITY_SERVICE);
这样的方法去拿到系统的服务。其实,我们并不是拿到了正真的系统服务,因为系统服务并不是在我们应用所在的进程中运行,所以我们拿到的是系统服务的入口对象。如下代码所示,最终我们会在SystemServiceRegistry中获得一个ActivityManger对象。Activity对象中通过ActivityManagerNative.getDefault()这个Binder对象来与系统服务进行通信。(关于Binder,后续会给一个大致的介绍,这边主要讲framework与应用的关系,所以不再继续深入下去)。
SystemServiceRegistry{
...
static{
...
registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
new CachedServiceFetcher<ActivityManager>() {
@Override
public ActivityManager createService(ContextImpl ctx) {
return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
}});
...
}
}
那么我们讲了这么多,有什么用呢。其实activity的启动与framework有莫大的联系,如果没有系统服务,那么我们的进程就无法显示,activity就无法创建,view就无法绘制,滑动点击事件也无法传递给应用,说到底,我们的应用构建在系统服务至上。在后续的介绍中,会着重去跟踪几个系统服务的类,所以说先在开始时从宏观上介绍一下我们到底和谁在通信,为什么要通信。
关联相应的源码
目前android studio是主流的android 开发软件,一般在android应用创建以后,会关联默认的android部分源码。如果希望获得其他版本的源码,可以通过SDK Manager进行下载。我使用的是android-23的源码。
如何调试Studio源码
点击菜单栏的“Run”->“Attach debugger to Android process”,选择需要调试的进程。然后再源码上加断点,debug就可以断在相应的位置。如果开始attach到app的进程,则看不到系统应用的进程的断点。如果需要调试ActivityMangerService这样的系统服务类的话,那么需要attach到system_process,然后对自己的应用进行断点调试。
如上图所示,我们算是成功的进行了断点。
总结
这里我们介绍了framework层和activity的关系,简单说了下如何调试源码。接下去,会介绍线程及线程入口,及android非常重要的looper机制。这也是理解activity运行机制的非常重要的一部分。