Android Application
先抛出如下三个问题:
- Application的作用
- Application的类继承关系及生命周期
- Application的初始化原理
Application的作用
- 保存应用进程内的全局变量。
Application是个系统组件,生命周期长,所以可以在里面存储些全局变量 - 初始化操作。
应用进程启动后做一些初始化操作,Application的创建是排在四大组件前 - 提供应用上下文。
我们调用一些系统api时,都需要用到Context,Application可以提供一个横跨应用进程生命周期的Context,也不用担心内存泄漏
注意点
Application是跟进程对应而不是跟应用对应,应用开了几个进程就会创建几个Application。
Application的类继承关系及生命周期
Application的类继承关系
public class Application extends ContextWrapper implements ComponentCallbacks2 {
}
public class ContextWrapper extends Context {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
protected void attachBaseContext(Context base) {
mBase = base;
}
}
- Application继承自ContextWrapper,ContextWrapper也就是Context的代理包装类。
- 所有的具体调用其实都是通过mBase,也就是说如果我们通过反射把mBase替换掉,那么Application的调用也会替换掉。
Application的生命周期
- 构造函数
- attachBaseContext
- onCreate
这三个函数是怎么调用的,以及调用的顺序是怎样的,首先我们先看看Application是怎么初始化的?我们从应用进程的入口函数看起,也就是ActivityThread的main:
// 代码来自Android23中:ActivityThread.java
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
}
private void attach(boolean system) {
......
final IActivityManager mgr = ActivityManagerNative.getDefault();
mgr.attachApplication(mAppThread);
}
- 这两个方法在上节 应用进程启动,已详细讲解过。
我们现在具体看看mgr.attachApplication中做了什么。
// 代码来自Android23中:ActivityServiceManager.java
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
attachApplicationLocked(thread, callingPid);
}
}
加synchronized主要是因为这是跑在AMS的binder线程中。
// 代码来自Android23中:ActivityServiceManager.java
boolean attachApplicationLocked(IApplicationThread thread, int pid) {
...
thread.bindApplication(...);
...
}
- 其中thread参数就是应用端发过来的binder对象。
- AMS在拿到应用进程的binder对象后,调用bindApplication。所以这又回到了应用进程中的方法。
我们看下应用进程是如何处理的:
// 代码来自Android23中:ActivityThread.java
public final void bindApplication(...){
...
AppBindData data = new AppBindData();
...
sendMessage(H.BIND_APPLICATION, data);
}
- 这个方法是跑在应用进程的binder线程中。
- 把所有的参数都封装在AppBindData中。
- 发送了一个消息丢到了应用的主线程。
接着往下看,在主线程中是如何处理BIND_APPLICATION这个消息的?通过handleBindApplication方法处理:
// 代码来自Android23中:ActivityThread.java
private void handleBindApplication(AppBindData data) {
...
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
...
Application app = packageInfo.makeApplication(false, mInstrumentation);
...
mInstrumentation.callApplicationOnCreate(app);
}
- getPackageInfoNoCheck这个主要是用来获取一个对象(LoadedApk),表示应用程序安装信息的。
- 拿到LoadedApk对象后,用makeApplication来创建Application对象。
- 最后的callApplicationOnCreate主要就是实现了app.onCreate(),也就是到了Application的onCreate的生命周期回调。
接下来看看LoadedApk.makeApplication方法是怎么创建Application的
// 代码来自Android23中:LoadedApk.java
public Application makeApplication(...){
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
...
app = mActivityThread.mInstrumentation.newApplication(...,appContext);
...
return app;
}
- 创建了一个appContext对象,类型为ContextImpl(Context的实现类)
- 以appContext为参数创建了一个Application对象。
继续往下跟踪看下Application是怎么创建的:
// 代码来自Android23中:Instrumentation.java
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
// 代码来自Android23中:Instrumentation.java
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
- 通过ClassLoader加载application的类(可能是我们自定义的application)。
- 通过类的构造函数去创建Application对象。
- 在通过attach把之前创建的Context传给Application。
- attach()方法最终会调到attachBaseContext()。
// 代码来自Android23中:Application.java
final void attach(Context context) {
attachBaseContext(context);
}
Application生命周期总结:

new Application() ---> application.attachBaseContext() ---> application.onCreate()
- 不要在Application的构造函数中使用它的上下文,因为那时context还未创建。
- 这几个函数都是在主线程中调用,所以Application的这几个回调方法中不能进行耗时操作。
- 关于本章涉及的Context,下章介绍
网友评论