安卓使用 Startup 管理三方 SDK 初始化

安卓使用 Startup 管理三方 SDK 初始化

一、为什么要使用 Startup?

1. 第三方 SDK 是怎么 "悄悄初始化" 的?

很多 popular SDK(如 Bugly、友盟、高德地图、MMKV、各类推送与统计 SDK)都在自己的 AAR 包里内置了一个 ContentProvider

它会在 AndroidManifest.xml 中注册类似这样的配置:

xml 复制代码
<provider
    android:name="com.xxx.XXXProvider"
    android:authorities="${applicationId}.xxx"
    android:exported="false" />

而在这个 Provider 的 onCreate() 里,它会偷偷执行 SDK 初始化:

java 复制代码
@Override
public void onCreate() {
    XXXSDK.init(getContext()); // 自动初始化
}

你什么都不用做,App 一启动,几十个 SDK 就在主线程排队初始化,直接拖慢冷启动速度。

2. 为什么 ContentProvider 会自动执行?

系统启动 App 的流程是固定的:

  1. Zygote 孵化出 App 进程
  2. 创建 Application,执行 attachBaseContext()
  3. 实例化并执行所有 Manifest 中注册的 ContentProvider
  4. 执行 Application.onCreate()
  5. 启动第一个 Activity

关键点:

ContentProvider 的 onCreate () 会在 Application.onCreate () 之前自动执行!

所以 SDK 利用这个 "系统钩子" 实现自动初始化,结果就是:

App 还没进入你的代码,已经被一堆 SDK 卡死在启动阶段。

3. Jetpack Startup 解决了什么问题?

App Startup 的核心使命非常简单:

用一个统一的 ContentProvider,替代所有 SDK 各自为政的 N 个 ContentProvider。

只保留一个:

xml 复制代码
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false" />

好处:

  1. 减少大量组件创建开销
  2. 统一管理 SDK 初始化顺序
  3. 支持依赖声明 → 自动拓扑排序
  4. 支持手动 / 懒加载控制

它不是禁用 ContentProvider,而是把被滥用的 "自动初始化钩子" 重新收归统一管理。

4.Startup 的核心作用总结

  1. 取消每个 SDK 自己私有的 Provider
  2. 把所有初始化逻辑集中到你写的 Initializer
  3. 通过 dependencies () 声明依赖 → 自动按顺序执行
  4. 不会乱并发、不会乱序、不会阻塞主线程

二、使用startup

1. 引入依赖

groovy 复制代码
implementation "androidx.startup:startup-runtime:1.2.0"

2. 新建多个Initializer类

MainInitializer.kt

备注:统一入口,可选

kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.AppInitializer
import androidx.startup.Initializer

class MainInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // ========== 这里写所有需要启动初始化的库 ==========
        println("初始化:MainInitializer")
        initNetwork(context)
        initPush(context)
//        initBugly(context)
//        initMMKV(context)
//        initRouter(context)
    }

    // 网络
    private fun initNetwork(context: Context) {
        AppInitializer.getInstance(context)
            .initializeComponent(NetworkInitializer::class.java)
    }

    // 推送
    private fun initPush(context: Context) {
        AppInitializer.getInstance(context)
            .initializeComponent(PushInitializer::class.java)
    }

    // 依赖:如果没有依赖其他Initializer,就空
    override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
CrashInitializer.kt
kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.Initializer

class CrashInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // 执行崩溃库初始化
        println("初始化:崩溃监控")
    }

    /**
     * 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
     * App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
     */
    override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
NetworkInitializer.kt
kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.Initializer

class NetworkInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // 执行网络库初始化
        println("初始化:网络框架")
    }

    /**
     * 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
     * App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
     */
    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(CrashInitializer::class.java)
}
PushInitializer.kt
kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.Initializer

class PushInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // 执行推送初始化
        println("初始化:推送服务")
    }

    /**
     * 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
     * App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
     */
    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(NetworkInitializer::class.java)
}

3. 初始化

方式 A:代码手动初始化(推荐)

更灵活、不抢启动、最安全:

kotlin 复制代码
// 在 Application 或 MainActivity 中
AppInitializer.getInstance(this)
    .initializeComponent(MainInitializer::class.java)

方式 B:XML 自动初始化(不推荐)

xml 复制代码
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">

    <meta-data
        android:name="com.example.startupdemo.initializer.MainInitializer"
        android:value="androidx.startup" />
</provider>

警告:如果不用 XML 配置,可以删除 <meta-data>,或使用 tools:node="remove" 让它失效。

4. 运行结果与demo

下载demo

复制代码
初始化:MainInitializer
初始化:崩溃监控
初始化:网络框架
初始化:推送服务

为什么顺序是这样?

  • NetworkInitializer 依赖 CrashInitializer
  • PushInitializer 依赖 NetworkInitializer
  • Startup 自动执行 拓扑排序 → 先依赖,后当前

由此实现:

  1. 初始化顺序完全可控
  2. 自动初始化 vs 懒加载 二选一
  3. 启动速度显著提升(减少 ContentProvider 数量)
  4. 代码结构更清晰、更好维护
相关推荐
jwn9992 小时前
Laravel3.x:PHP框架的经典里程碑
android
lishutong10062 小时前
基于 Perfetto 与 AI 的 Android 性能自动化诊断方案
android·人工智能·自动化
REDcker2 小时前
Android Bionic Libc 原理与实现综述
android·c++·c·ndk·native·bionic
葱段2 小时前
Flutter 设置Android System Navigation/Status Bar背景色
android·flutter
半条-咸鱼2 小时前
如何通过 ADB 连接安卓设备(USB + 无线 TCP/IP)
android·adb
vonlycn2 小时前
Android Studio 5.3.3 新项目编译报错解决
android·ide·android studio
fengci.2 小时前
php反序列化(复习)(第二章)
android·开发语言·学习·php
sickworm陈浩2 小时前
为 300W 行的安卓老工程落地可迭代的 AI 知识库
android·ai编程
jwn9992 小时前
Laravel 9.x重磅新特性解析
android