Jetpack-Startup源码解析

Startup源码解析

源码版本:
* Startup:1.2.0
* 更新时间:2025-3月

导航:
* Jetpack-Lifecycle源码解析
* Jetpack-LiveData源码解析
* Jetpack-ViewModel源码详解
* Jetpack-Startup源码详解
* 更多的文章看这里:主页

使用

实现Initializer

class WorkManagerInitializer : Initializer<WorkManager> {

    override fun create(context: Context): WorkManager {
        // 初始化WorkManager
        val configuration = Configuration.Builder().build()
        WorkManager.initialize(context, configuration)
        // 返回WorkManager初始化后的实例,以便通过AppInitializer.getInstance(context).initializeComponent(WorkManagerInitializer::class.java)初始化并获取。
        return WorkManager.getInstance(context)
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        // 无依赖其它库
        return emptyList()
    }
}

因为WorkManager不依赖于任何其它库,所以该dependencies()方法返回一个空列表

class ExampleLoggerInitializer : Initializer<ExampleLogger> {
    override fun create(context: Context): ExampleLogger {
        // 初始化ExampleLogger,并返回其对象,以便通过AppInitializer.getInstance(context).initializeComponent(ExampleLoggerInitializer::class.java)初始化并获取。
        return ExampleLogger(WorkManager.getInstance(context))
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        // 依赖WorkManagerInitializer
        return listOf(WorkManagerInitializer::class.java)
    }
}

因为ExampleLogger依赖于WorkManager,所以该dependencies()方法返回包含WorkManagerInitializer列表,使其在它之前初始化

初始化Initializer

自动初始化组件

在清单文件中添加

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data  
        android:name="com.example.ExampleLoggerInitializer" // 要初始化的Initializer类名全路径
        android:value="androidx.startup" />
</provider>

自动初始化组件,其为在应用启动时初始化组件。不需要为WorkManagerInitializer添加<meta-data>条目,因为它是ExampleLoggerInitializer依赖项,当然声明了也不会有问题(因为已经被初始了,则不会再进行初始化了,详细看源码介绍)。

说明:
1. 该provider声明格式固定,只需要修改<meta-data>name即可。
2. 该<meta-data>顺序,决定着初始化的顺序
3. 该tools:node="merge"属性确保清单合并工具正确解决任何冲突条目

手动初始化组件

手动初始化组件,其意为就是不自动初始化组件,所以您必须停用自动初始化,其又称为延迟初始化

停用单个组件的自动初始化

要停用单个组件的自动初始化,例如:

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data android:name="com.example.ExampleLoggerInitializer"
              tools:node="remove" />
</provider>

移除清单中该组件的初始化程序的 <meta-data> 条目,或者您可以在条目中使用 tools:node="remove",以确保合并工具还会将相应条目从其他所有列表中删除

说明:
1. 停用组件的自动初始化也会停用该组件的依赖项自动初始化
2. tools:node="remove",从合并后的清单移除此元素。

停用所有组件的自动初始化

要停用所有自动初始化,请删除 InitializationProvider

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove" />

停用所有组件的自动初始化,将tools:node="remove"声明到InitializationProviderprovider上即可,其它保持不变或删除掉全部<meta-data>都可以。

说明:
1. 不推荐停用所有组件的自动初始化,因为会停用掉所有使用startup初始化三方库(如lifecycle库的ProcessLifecycleInitializer),导致得需要手动初始化所有使用startup库的三方库,不方便后续维护。

手动初始化组件

val result = AppInitializer.getInstance(context)
    .initializeComponent(ExampleLoggerInitializer::class.java)

手动初始化组件,调用AppInitializer.initializeComponent()方法即可,以上代码手动初始化ExampleLogger,又因为ExampleLogger依赖WorkManager,所以WorkManager也完成了初始化。

说明:
1. 其返回值resultExampleLoggerInitializercreate()方法返回的ExampleLogger实例。
2. 如果AppInitializer.initializeComponent()方法初始化的Initializer已经初始化完成,再次调用则不会再次初始化,而是会返回第一次初始化结果值(如初始化ExampleLoggerInitializer,始终会返回第一次初始化ExampleLogger实例)。

源码

实现Initializer

Initializer类

public interface Initializer<T> {

    // 初始化组件
    @NonNull
    T create(@NonNull Context context);

    // 这个Initializer依赖的依赖项列表。这是用来确定Initializer的初始化顺序。
    // 例如,如果一个初始化器 B 定义了另一个初始化器 A 作为它的依赖,那么 A 在 B 之前被初始化。
    @NonNull
    List<Class<? extends Initializer<?>>> dependencies();
}

Initializer类,为初始化器接口,这个接口定义了两个重要的方法:

  • create()方法,它包含初始化组件所需的所有操作,并返回T的实例
  • dependencies()方法,它返回Initializer所依赖的其它Initializer<T>对象的列表。您可以使用此方法控制app启动时运行initializers顺序

初始化Initializer

自动初始化组件

我们先来看一下startup库的清单文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="androidx.startup" >

    <uses-sdk android:minSdkVersion="21" />

    <application>
        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge" />
    </application>

</manifest>

里面声明了最小SDK版本21,以及声明了一个ContentProvider,它是InitializationProvider,接下来我们再来看一下InitializationProvider类。

InitializationProvider类

public class InitializationProvider extends ContentProvider {

    @Override
    public final boolean onCreate() {
        Context context = getContext();
        if (context != null) {
            Context applicationContext = context.getApplicationContext();
            if (applicationContext != null) {                AppInitializer.getInstance(context).discoverAndInitialize(getClass());
            } else {
                StartupLogger.w("Deferring initialization because `applicationContext` is null.");
            }
        } else {
            throw new StartupException("Context cannot be null");
        }
        return true;
    }

    @Nullable
    @Override
    public final Cursor query(
            @NonNull Uri uri,
            @Nullable String[] projection,
            @Nullable String selection,
            @Nullable String[] selectionArgs,
            @Nullable String sortOrder) {
        throw new IllegalStateException("Not allowed.");
    }

    @Nullable
    @Override
    public final String getType(@NonNull Uri uri) {
        throw new IllegalStateException("Not allowed.");
    }

    @Nullable
    @Override
    public final Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        throw new IllegalStateException("Not allowed.");
    }

    @Override
    public final int delete(
            @NonNull Uri uri,
            @Nullable String selection,
            @Nullable String[] selectionArgs) {
        throw new IllegalStateException("Not allowed.");
    }

    @Override
    public final int update(
            @NonNull Uri uri,
            @Nullable ContentValues values,
            @Nullable String selection,
            @Nullable String[] selectionArgs) {
        throw new IllegalStateException("Not allowed.");
    }
}

InitializationProvider类,它是一个ContentProvider,在其onCreate()方法里面调用了AppInitializer.getInstance(context).discoverAndInitialize(),我们先来看一下AppInitializer.getInstance(context)方法,然后再看一下其discoverAndInitialize()方法。

说明:
1. ApplicationContentProviderActivityonCreate()执行顺序:Application.attachBaseContext() -> ContentProvider.onCreate() -> Application.onCreate() -> Activity.onCreate()

AppInitializer –> getInstance方法

public final class AppInitializer {

    // 单例AppInitializer实例
    private static volatile AppInitializer sInstance;

    // 获取单例AppInitializer的实例
    @NonNull
    @SuppressWarnings("UnusedReturnValue")
    public static AppInitializer getInstance(@NonNull Context context) {
        if (sInstance == null) {
            synchronized (sLock) {
                if (sInstance == null) {
                    sInstance = new AppInitializer(context);
                }
            }
        }
        return sInstance;
    }

}

AppInitializer.getInstance(context)方法,为单例获取AppInitializer的实例。

AppInitializer的创建

// Tracing
private static final String SECTION_NAME = "Startup";

// 单例AppInitializer实例
private static volatile AppInitializer sInstance;

// 线程锁
private static final Object sLock = new Object();

// 已经初始化Initializer的Map集合,key为Initializer的class,value为Initializer.onCreate()方法的返回值。
@NonNull
final Map<Class<?>, Object> mInitialized;

// 已发现Initializer的Set集合,value为Initializer的class。
@NonNull
final Set<Class<? extends Initializer<?>>> mDiscovered;

@NonNull
final Context mContext;

// 创建AppInitializer
AppInitializer(@NonNull Context context) {
    mContext = context.getApplicationContext();
    mDiscovered = new HashSet<>();
    mInitialized = new HashMap<>();
}

AppInitializer –> discoverAndInitialize方法

void discoverAndInitialize(
        @NonNull Class<? extends InitializationProvider> initializationProvider) {
    try {
        Trace.beginSection(SECTION_NAME);
        // 获取InitializationProvider的ProviderInfo
        ComponentName provider = new ComponentName(mContext, initializationProvider);
        ProviderInfo providerInfo = mContext.getPackageManager()
                .getProviderInfo(provider, GET_META_DATA);
        // 获取其<meta-data>信息
        Bundle metadata = providerInfo.metaData;
        // 发现并初始化
        discoverAndInitialize(metadata);
    } catch (PackageManager.NameNotFoundException exception) {
        throw new StartupException(exception);
    } finally {
        Trace.endSection();
    }
}

上面获取到metaData信息后调用了下面方法

// 已发现Initializer的Set集合,value为Initializer的class。
@NonNull
final Set<Class<? extends Initializer<?>>> mDiscovered;   

@SuppressWarnings("unchecked")
void discoverAndInitialize(@Nullable Bundle metadata) {
    // 获取字符串,值为"androidx.startup"
    String startup = mContext.getString(R.string.androidx_startup);
    try {
        // 判断metadata为不为null,即有没有配置<meta-data>,没配置则不处理。
        if (metadata != null) {
            // 初始化中Initializer的Class集合
            Set<Class<?>> initializing = new HashSet<>();
            // 获取metadata中所有的key,即获取所有<meta-data>内的android:name。
            Set<String> keys = metadata.keySet();
            // 遍历metadata中所有的key
            for (String key : keys) {
                // 获取metadata中的值即获取<meta-data>内的android:value。
                String value = metadata.getString(key, null);
                // 判断<meta-data>内的android:value为"androidx.startup"
                if (startup.equals(value)) {
                    // 获取<meta-data>内的android:name指定的class
                    Class<?> clazz = Class.forName(key);
                    // 判断<meta-data>内的android:name指定的class是否是Initializer的子类。
                    if (Initializer.class.isAssignableFrom(clazz)) {
                        // 是Initializer子类,则强转。
                        Class<? extends Initializer<?>> component =
                                (Class<? extends Initializer<?>>) clazz;
                        // 添加到mDiscovered(已发现)集合
                        mDiscovered.add(component);
                        // 打印日志
                        if (StartupLogger.DEBUG) {
                            StartupLogger.i(String.format("Discovered %s", key));
                        }
                    }
                }
            }

            // 请在发现完成后进行初始化。这样,isEagerlyInitialized的检查是正确的。
            for (Class<? extends Initializer<?>> component : mDiscovered) {
                // 初始化component,即初始化<meta-data>内的android:name指定的class。
                doInitialize(component, initializing);
            }
        }
    } catch (ClassNotFoundException exception) {
        throw new StartupException(exception);
    }
}

AppInitializer.discoverAndInitialize()方法,为发现并初始化Initializer,找到清单文件配置的所有Initializer,然后调用doInitialize()方法进行初始化操作。

说明:
1. <meta-data>内的android:value,必须为androidx.startup
2. <meta-data>内的android:name,必须为Initializer子类类名全路径
3. 在清单文件配置的所有Initializer,都会添加到mDiscovered(已发现)集合

我们再来看一下AppInitializer.doInitialize()方法。

AppInitializer –> doInitialize方法

// 已经初始化Initializer的Map集合,key为Initializer的class,value为Initializer.onCreate()方法的返回值。
@NonNull
final Map<Class<?>, Object> mInitialized;

// 做初始化
private <T> T doInitialize(
        @NonNull Class<? extends Initializer<?>> component,
        @NonNull Set<Class<?>> initializing) {
    boolean isTracingEnabled = Trace.isEnabled();
    try {
        if (isTracingEnabled) {
            Trace.beginSection(component.getSimpleName());
        }
        // 如果这个类正在初始化中,再初始化,则抛出异常。
        if (initializing.contains(component)) {
            String message = String.format(
                    "Cannot initialize %s. Cycle detected.", component.getName()
            );
            throw new IllegalStateException(message);
        }
        // 结果
        Object result;
        // 判断这个类是否被初始化过,防止重复初始化。
        if (!mInitialized.containsKey(component)) {
            // 没初始化过,则进行初始化,并记录其create的结果。
            // 添加到正在初始化中的集合,标记正在初始化中。
            initializing.add(component);
            try {
                // 反射创建对象
                Object instance = component.getDeclaredConstructor().newInstance();
                // 强转,因为component实现了Initializer,所以没问题。
                Initializer<?> initializer = (Initializer<?>) instance;
                // 获取其依赖的Initializer列表
                List<Class<? extends Initializer<?>>> dependencies =
                        initializer.dependencies();

                // 如果其依赖的Initializer列表不为空,就先初始化依赖列表。
                if (!dependencies.isEmpty()) {
                    // 遍历其依赖的Initializer列表
                    for (Class<? extends Initializer<?>> clazz : dependencies) {
                        // 判断其依赖的Initializer,是否已经被初始化过。
                        if (!mInitialized.containsKey(clazz)) {
                            // 没初始化过,则进行递归初始化。
                            // -说明:在此会等待所有依赖完成才会执行后续代码。
                            doInitialize(clazz, initializing);
                        }
                    }
                }
                // 打印日志:初始化中的组件名。
                if (StartupLogger.DEBUG) {
                    StartupLogger.i(String.format("Initializing %s", component.getName()));
                }
                // 调用Initializer的create()方法进行初始化,并记录其返回结果。
                result = initializer.create(mContext);
                // 打印日志:初始化完成的组件名。
                if (StartupLogger.DEBUG) {
                    StartupLogger.i(String.format("Initialized %s", component.getName()));
                }
                // 在正在初始化中的集合中移除,标记已经初始化过。
                initializing.remove(component);
                // 存入已经初始化的Initializer,以及其create()方法返回的结果。
                mInitialized.put(component, result);
            } catch (Throwable throwable) {
                throw new StartupException(throwable);
            }
        } else {
            // 已经初始化过,则获取其create()的结果。
            result = mInitialized.get(component);
        }
        // 返回initializer.create()的结果
        return (T) result;
    } finally {
        Trace.endSection();
    }
}

AppInitializer.doInitialize()方法,为真正的初始化Initializer的方法,它反射创建Initializer对象,并调用其create()方法通知内部的初始化,并mInitialized记录create()方法的返回值

说明:
1. 如果这个Initializer未被初始化,则反射创建这个Initializer对象,并调用其create()方法通知内部的初始化,并将其create()方法的结果添加到在mInitialized中以便后续获取;否则,则从mInitialized中获取第一次初始化结果值,使其不会频繁创建这个Initializer对象。
2. 如果要创建的Initializer,依赖其它Initializer,则会进行循环递归初始化其它Initializer,使其它Initializer全部初始化完成,才会执行此Initializercreate()方法。

手动初始化组件

AppInitializer –> initializeComponent方法

// 初始化Initializer类
@NonNull
@SuppressWarnings("unused")
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
    return doInitialize(component);
}
// 线程锁
private static final Object sLock = new Object();

@NonNull
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
<T> T doInitialize(@NonNull Class<? extends Initializer<?>> component) {
    Object result;
    // 同步,保证线程安全。
    synchronized (sLock) {
        result = mInitialized.get(component);
        if (result == null) {
            result = doInitialize(component, new HashSet<Class<?>>());
        }
    }
    return (T) result;
}

AppInitializer.initializeComponent()方法,直接调用了doInitialize()方法进行创建,并返回了其doInitialize()方法的结果值(即Initializer.create()方法的返回值)。

说明:
1. 只有initializeComponent()方法才能拿到Initializercreate()方法的返回值,不管是自动初始化ContentProvider存入,还是手动初始化(调用initializeComponent()存入,都可以再次调用initializeComponent()方法获取到其在create()方法的返回值
2. doInitialize()方法,因为使用了synchronized代码块,且锁sLock静态的(唯一),所以当有线程正在执行doInitialize()方法时,其它线程再执行doInitialize()方法时都得等待上个线程执行完成
3. 由于initializeComponent()方法调用了doInitialize()方法(内部使用了synchronized),导致其执行中,其它都得等待。例如:AB耗时所以分别在一个子线程执行initializeComponent()方法,C主线程执行,使其三个分别在三个线程执行,以达到并发的效果,但是结果为:A执行中,BC等待A执行完成,未达到并发效果。

其它源码

AppInitializer –> isEagerlyInitialized方法

// Initializer是否是被急切地初始化
public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) {
    // 如果从未调用过discoverAndInitialize(),即不是通过清单文件初始化,则没有急于初始化任何内容。
    return mDiscovered.contains(component);
}

AppInitializer.isEagerlyInitialized()方法,为Initializer是否是被急切地初始化,即是否是通过清单文件配置初始化。

优缺点

优点

  • 提供了一个规则,可以让所有的三方库,使用同一个ContentProvider在其库内部进行初始化减少了初始化代码优化创建多个ContentProvider造成的性能、时间损耗
  • 支持初始化的顺序以及依赖关系

缺点

  • 只能在主线程初始化,不支持子线程初始化。
  • 反射创建Initializer类,对性能有稍微影响。

总结

以上就是全面的Jetpack-Startup源码了!欢迎大家点赞、收藏,以方便您后续查看,之后会出Jetpack其它源码系列,请及时关注。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
京ICP备18058279号-1