Skip to content

一个App会创建多少个Application对象

默认情况下只有一个。

Application 是跟着进程走的,不是跟着整个 App 走的。系统在创建进程时就会实例化它,并且在这个进程的整个生命周期内只存在这一份。 官方文档写得很清楚:Application(或你的子类)是在该应用/包对应的进程被创建时、在任何其他类之前就被实例化的。 alt text

所以单进程 App 里:

  • Application 实例只有 1 个
  • onCreate() 只走一次

这是绝大多数人的日常认知,也是正确的。

1. 一旦开启多进程,情况就变了

Android 允许通过 android:process 让组件跑在不同进程。每个进程都会各自创建一份 Application。

结论很直接:

  • 单进程 → 1 个 Application,onCreate() 执行 1 次
  • 多进程(N 个进程)→ N 个 Application,onCreate() 执行 N 次

验证方式很简单:在自定义 Application 的 onCreate() 里打印当前进程名 + 对象的 hashCode(或者用 Unsafe 拿真实物理地址)。启动带 :remote:push 之类 process 的组件后,你会看到不同进程对应完全不同的实例。即使虚拟地址偶尔看起来一样,物理地址是分开的。

源码路径也支持这个结论。进程起来后会走到 ActivityThread.handleBindApplication(),里面通过 LoadedApk.makeApplication() 去创建 Application。每个进程都有自己独立的 ActivityThread 和 LoadedApk,所以必然各创建一份。

2. 为什么必须每个进程一份?

进程之间内存完全隔离,不能直接共享 Java 对象。Application 本质上是这个进程内的全局 Context 持有者和初始化入口,它只能跟着进程走。主进程有主进程的,子进程有子进程的,彼此互不相干,也不能互相访问对方的成员变量。

这也是很多 SDK 文档会特别提醒「如果你继承了 Application,必须保证它是多进程安全的」的原因。

3. 实际开发里要注意的点

初始化逻辑最好做进程判断,只在主进程做重活:

Kotlin
override fun onCreate() {
    super.onCreate()
    if (packageName == Application.getProcessName()) {
        // 只在主进程初始化
    }
}

onCreate() 里别塞太多耗时操作,多进程场景下启动成本会被放大。

ContentProvider 的 onCreate() 比 Application 还早,而且默认只在主进程创建(除非你指定了 process),所以不少框架会用它来做「只执行一次」的初始化。

ActivityThread 里确实有个 mAllApplications 列表,但正常 App 里通常就一个。出现多个的情况多半是插件化或特殊框架搞出来的,不属于常规行为。

最终结论:

Application 是进程级单例,不是应用级全局单例。单进程永远只有一个,多进程就有几个进程就有几个。这是由 Android 的进程隔离模型和 ActivityThreadLoadedApk.makeApplication() 的创建机制共同决定的。