Android Framework系列4-2 Application

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生命周期总结:

Application.png

new Application() ---> application.attachBaseContext() ---> application.onCreate()

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

你可能感兴趣的:(Android Framework系列4-2 Application)