android Initializer 启动入门


一、整体大图

这是一个「去 Application 化」的初始化设计

  • 不在 Application.onCreate() 里手写初始化逻辑
  • 改用 androidx.startup.Initializer
  • 通过 Manifest 声明 + 依赖关系 自动完成初始化顺序

初始化顺序(非常关键):

复制代码
Application 启动
  ↓
AndroidX Startup 扫描 Manifest
  ↓
KoinInitializer.create()        ← 初始化 DI 容器
  ↓
PlayxxxManagerInitializer.create()  ← 依赖 Koin,可注入对象

二、第一部分:AndroidManifest.xml(入口)

xml 复制代码
<meta-data
    android:name="com.xx.a"
    android:value="androidx.startup" />

<meta-data
    android:name="com.xxx.b"
    android:value="androidx.startup" />

1️⃣ 这是干嘛的?

这是 AndroidX Startup 的注册方式:

  • 每一个 <meta-data android:value="androidx.startup"/>
  • 就表示:这是一个 Initializer,需要在 App 启动时自动执行

不需要你在任何地方手动调用


2️⃣ Startup 在什么时候执行?

  • ContentProvider 阶段(比 Application.onCreate 还早)
  • 系统启动 App → Startup Provider 被加载 → 执行 Initializer

⚠️ 所以这些代码 都发生在 App 冷启动最早期


三、第二部分:KoinInitializer(DI 容器初始化)

kotlin 复制代码
class KoinInitializer : Initializer<Boolean> {

1️⃣ 它的职责(非常单一)

只做一件事:启动 Koin 容器

kotlin 复制代码
startKoin {
    androidLogger(...)
    androidContext(context)
    modules(koinModules)
}

这一步完成后:

  • 全局 Koin 容器建立
  • 所有 single / factory / viewModel 都可被注入
  • by inject() 才能正常工作

2️⃣ 为什么要用 Initializer 而不是 Application?

优点非常明显:

方式 问题
Application.onCreate 容易膨胀、耦合严重
AndroidX Startup 模块化、自动排序、可独立测试

尤其在 多模块 / 车机项目 中,这是业界推荐写法


3️⃣ dependencies() 为什么返回空?

kotlin 复制代码
override fun dependencies() = mutableListOf<Class<out Initializer<*>>>()

表示:

  • 它不依赖任何其他初始化器
  • 它是"最底层基础设施"

👉 这也是为什么 其他 Initializer 都要依赖它


四、第三部分:PlayControlManagerInitializer(业务初始化)

kotlin 复制代码
class PlayControlManagerInitializer :
    Initializer<PlayControlManager>,
    KoinComponent

这是整套设计的 核心亮点


四-1:为什么要实现 KoinComponent?

kotlin 复制代码
private val playerStatusSavedListener: PlayerStatusSavedListener by inject()

原理解释:

  • Initializer 本身 不是 Android 组件
  • 没有 Context / Lifecycle / ViewModelScope
  • 无法自动注入

👉 实现 KoinComponent 后:

  • 当前类 可以访问 Koin 容器
  • by inject() 才能生效

⚠️ 前提:

Koin 容器必须已经 startKoin() 完成


四-2:create() 里做了什么?

kotlin 复制代码
override fun create(context: Context): PlayControlManager {

初始化顺序拆解:

① 初始化 Repository 工厂
kotlin 复制代码
RepositoryFactory.instance.init(context)
  • 建立数据访问层
  • 为播放器提供数据支持

② 初始化播放控制单例
kotlin 复制代码
PlayxxManager.instance.init(
    context,
    RepositoryFactory.instance,
    RepoConstant.SUPPLIER_LOCAL_MUSIC
)
  • 标准 饿汉 / 单例初始化
  • 绑定数据源 & Context

③ 设置默认播放模式
kotlin 复制代码
PlayxxManager.instance.setDefaultPlayMode(PlayMode.LoopPlay)

④ 注入 & 注册 Listener(关键)
kotlin 复制代码
PlayxxManager.instance.addPlayerStatusListener(playerxxListener)

⚠️ 这里的 playerStatusSavedListener:

  • 来自 Koin 注入
  • 依赖 KoinInitializer 已执行

四-3:dependencies() 的真正意义(最关键)

kotlin 复制代码
override fun dependencies() =
    mutableListOf(LogInitializer::class.java, KoinInitializer::class.java)

这是整个设计的 "顺序控制器"

含义是:

在执行 PlayxxManagerInitializer.create() 之前,必须先执行:

  1. LogInitializer
  2. KoinInitializer

为什么一定要依赖 KoinInitializer?

因为你这里用了:

kotlin 复制代码
by inject()

如果 Koin 没启动:

  • ❌ 注入直接 crash
  • ❌ NoBeanDefFoundException

五、三者之间的关系(总结图)

复制代码
AndroidManifest.xml
        ↓
AndroidX Startup 扫描
        ↓
KoinInitializer
    ├─ startKoin()
    └─ 建立 DI 容器
        ↓
PlayxxManagerInitializer
    ├─ 通过 Koin 注入 Listener
    ├─ 初始化 Repository
    ├─ 初始化 PlayControlManager
    └─ 注册监听器

相关推荐
小宋102142 分钟前
Agent轨迹级评测实战:工具选择、预算超限与回归门禁
android·网络·人工智能·回归
墨天梦3 小时前
D05_ViewModel与单向数据流
android·kotlin
蒸鱼Yuzheng4 小时前
Android 构建可复现性:APK 指纹、文件级差异与供应链审计
android·apk·devops·软件供应链·可复现构建
墨天梦6 小时前
D03_Compose列表与稳定身份
android·gitee·kotlin
萌新杰少7 小时前
Kuikly股票查看软件开发体验——SaiRen
android·kotlin·客户端
vilya7 小时前
把 Python 塞进 APK:Chaquopy 打包实践
android·python
用户92817267390167 小时前
Android Compose版本的AI组件库来了。
android·kotlin
知昂七昂7 小时前
00-02:AOSP 源码阅读环境与检索方法论源码剖析(Android 16 / aosp-main)
android
知昂七昂7 小时前
00-01:AOSP 源码仓库结构与 repo 工作流源码剖析(Android 16 / aosp-main)
android·google
跨境数据猎手7 小时前
Android Native 层黑盒调用实战:unidbg 模拟执行 so 的原理
android