Jetpack-Startup源码解析

Startup源码解析

源码版本:

  • Startup:1.1.0

使用

实现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>

禁用单个组件的自动初始化,将tools:node="remove"声明到指定<meta-data>上即可,其它保持不变。

说明:

  1. 如果<meta-data>是自己的(可修改),则删除指定的<meta-data>即可;如果<meta-data>不是自己的(如三方库,不可修改),则使用tools:node="remove"声明即可。
  2. 禁用组件的自动初始化也会禁用该组件的依赖项自动初始化
  3. tools:node="remove",从合并后的清单移除此元素。

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

<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="14"
        android:targetSdkVersion="30" />

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

</manifest>

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

InitializationProvider类

public class InitializationProvider extends ContentProvider {
    @Override
    public final boolean onCreate() {
        Context context = getContext();
        if (context != null) {
            AppInitializer.getInstance(context).discoverAndInitialize();
        } 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 --> discoverAndInitialize方法

public final class AppInitializer {

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

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

    // 发现并初始化
    @SuppressWarnings("unchecked")
    void discoverAndInitialize() {
        try {
            Trace.beginSection(SECTION_NAME);
            // 获取InitializationProvider的ProviderInfo
            ComponentName provider = new ComponentName(mContext.getPackageName(),
                    InitializationProvider.class.getName());
            ProviderInfo providerInfo = mContext.getPackageManager()
                    .getProviderInfo(provider, GET_META_DATA);
            // 获取<meta-data>信息
            Bundle metadata = providerInfo.metaData;
            // 获取字符串,值为"androidx.startup"
            String startup = mContext.getString(R.string.androidx_startup);
            // 判断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));
                            }
                            // 初始化component,即初始化<meta-data>内的android:name指定的class。
                            doInitialize(component, initializing);
                        }
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
            throw new StartupException(exception);
        } finally {
            Trace.endSection();
        }
    }
}

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方法

public final class AppInitializer {

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

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

    // 做初始化
    @NonNull
    @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
    <T> T doInitialize(
            @NonNull Class<? extends Initializer<?>> component,
            @NonNull Set<Class<?>> initializing) {
        // 同步,保证线程安全。
        synchronized (sLock) {
            boolean isTracingEnabled = Trace.isEnabled();
            try {
                if (isTracingEnabled) {
                    // Use the simpleName here because section names would get too big otherwise.
                    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()));
                        }
                        // 调用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()方法通知内部的初始化,并返回create()方法的返回值

说明:

  1. 如果这个Initializer未被初始化,则反射创建这个Initializer对象,并调用其create()方法通知内部的初始化,并将其create()方法的结果添加到在mInitialized中以便后续获取;否则,则从mInitialized中获取第一次初始化结果值,使其不会频繁创建这个Initializer对象。
  2. 如果要创建的Initializer,依赖其它Initializer,则会进行循环递归初始化其它Initializer,使其它Initializer全部初始化完成,才会执行此Initializercreate()方法。
  3. doInitialize()方法,因为使用了synchronized代码块,且锁sLock静态的(唯一),所以当有线程正在执行doInitialize()方法时,其它线程再执行doInitialize()方法时都得等待上个线程执行完成

手动初始化组件

AppInitializer --> initializeComponent方法

// 初始化Initializer类
@NonNull
@SuppressWarnings("unused")
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
    return doInitialize(component, new HashSet<Class<?>>());
}

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

说明:

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

其它源码

AppInitializer --> isEagerlyInitialized方法

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

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

优缺点

优点

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

缺点

  • 不支持多线程并发初始化。
  • 反射创建Initializer类,对性能有稍微影响。
暂无评论

发送评论 编辑评论


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