安卓使用 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. 代码结构更清晰、更好维护
相关推荐
qq_452396231 天前
第十篇:《自动化处理验证码:OCR、接口绕过与第三方服务》
android·自动化·ocr
a8a3021 天前
Laravel 10.x核心特性深度解析
android
angerdream1 天前
Android手把手编写儿童手机远程监控App之UUID
android
dalancon1 天前
Android OomAdjuster流程
android
河婆墟邓紫棋1 天前
MIUI中的权限
android·github
我命由我123451 天前
Java 开发 - CountDownLatch 不需要手动关闭
android·java·开发语言·jvm·kotlin·android studio·android-studio
众少成多积小致巨1 天前
GNU Make 核心指南
android·c++
凛_Lin~~1 天前
安卓进程保活方案记录(双重fork+文件锁+手搓parcel)
android·安卓
海天鹰1 天前
安卓相机:获取最近拍摄的照片缩略图做相册按钮图标
android
tongyiixiaohuang1 天前
技术案例分享:金蝶云星空客户数据同步到MySQL的实现
android·数据库·mysql