[Jetpack][App Startup]源码分析

723 阅读3分钟

[Jetpack][App Startup]源码分析

简介

App Startup是Jetpack组件之一。可以阅读官方文档了解基本使用方式。

App Startup提供了一个Initializer接口将各个初始化工作隔离开来:

/**
 * {@link Initializer}s can be used to initialize libraries during app startup, without
 * the need to use additional {@link android.content.ContentProvider}s.
 *
 * @param <T> The instance type being initialized
 */
public interface Initializer<T> {

    /**
     * Initializes and a component given the application {@link Context}
     *
     * @param context The application context.
     */
    @NonNull
    T create(@NonNull Context context);

    /**
     * @return A list of dependencies that this {@link Initializer} depends on. This is
     * used to determine initialization order of {@link Initializer}s.
     * <br/>
     * For e.g. if a {@link Initializer} `B` defines another
     * {@link Initializer} `A` as its dependency, then `A` gets initialized before `B`.
     */
    @NonNull
    List<Class<? extends Initializer<?>>> dependencies();
}

其中:

  1. create方法中进行当前的初始化工作
  2. dependencies方法返回当前初始化需要的依赖项。依赖项是一个Initializer接口列表,依赖项会先于当前Initializer执行

通过Initializer接口,可以把复杂的初始化工作串起来,不过串起来也需要我们指定初始执行的Initializer。有两种方式可以指定初始执行的Initializer。

  1. 通过content-provider声明的方式
  2. 通过AppInitializer指定

content-provider的方式想来在实际项目会用的少一些,毕竟还是代码的控制力度更好一些。通过AppInitializer指定初始Initializer方式如下:

val result = AppInitializer.getInstance(this.applicationContext)
            .initializeComponent(TestInitializer::class.java)

result即可Initializer产生的结果。
接下来就从AppInitializer着手分析App Startup的源码。

源码分析

AppInitializer初始化


首先AppInitializer是一个单例类,使用懒汉方式实现的单例:

public static AppInitializer getInstance(@NonNull Context context) {
    if (sInstance == null) {
        synchronized (sLock) {
            if (sInstance == null) {
                sInstance = new AppInitializer(context);
            }
        }
    }
    return sInstance;
}

@NonNull
final Map<Class<?>, Object> mInitialized;
@NonNull
final Set<Class<? extends Initializer<?>>> mDiscovered;

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

我们主要关注构造的过程,可以看到构造了一个Map和一个Set,也很好理解,毕竟多个Initializer总是需要容器保存的。其中:

  1. mInitialized保存已经完成初始化的Initializer。每个Initializer只能被初始化一次,简单说即其create方法只会被调用一次。其中Key为Initializer的class对象,value为Initializer的create返回值。
  2. mDiscovered保存发现的Initializer。当使用content-provider方式配置Initializer,则AppInitializer会根据content-provider内部的meta-data自动的发现关联的Initializer。

### Initializer初始化
/**
 * Initializes a {@link Initializer} class type.
 *
 * @param component The {@link Class} of {@link Initializer} to initialize.
 * @param <T>       The instance type being initialized
 * @return The initialized instance
 */
@NonNull
@SuppressWarnings("unused")
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
    return doInitialize(component, new HashSet<Class<?>>());
}

@NonNull
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
<T> T doInitialize(
        @NonNull Class<? extends Initializer<?>> component,
        @NonNull Set<Class<?>> initializing) {
    //可以看到加了一个很粗的锁
    //先不论性能,这里至少保证了初始化过程是线程安全的
    synchronized (sLock) {
        try {
            //这里的代码主要是为了防止Initializer的循环依赖
            if (initializing.contains(component)) {
                String message = String.format(
                        "Cannot initialize %s. Cycle detected.", component.getName()
                );
                throw new IllegalStateException(message);
            }
            Object result;
            //已完成初始化的Initializer不会被再次初始化
            //那么多次调用initializeComponent并不会带来多大的性能损耗
            if (!mInitialized.containsKey(component)) {
                initializing.add(component);
                try {
                    //反射创建Initializer的实例
                    Object instance = component.getDeclaredConstructor().newInstance();
                    Initializer<?> initializer = (Initializer<?>) instance;
                    
                    //获取Initializer的依赖项
                    List<Class<? extends Initializer<?>>> dependencies =
                            initializer.dependencies();
                    if (!dependencies.isEmpty()) {
                        for (Class<? extends Initializer<?>> clazz : dependencies) {
                            if (!mInitialized.containsKey(clazz)) {
                                //开始递归过程
                                //保证依赖先于Initializer先被初始化
                                doInitialize(clazz, initializing);
                            }
                        }
                    }
                    
                    //真正执行Initializer的初始化
                    //Initializer的初始化是在当前线程执行的,并没有什么异步处理
                    //如果在主线程调用初始化,那么初始化工作也会在主线程执行
                    result = initializer.create(mContext);
                    //更新容器
                    initializing.remove(component);
                    mInitialized.put(component, result);
                } catch (Throwable throwable) {
                    throw new StartupException(throwable);
                }
            } else {
                //如果Initializer已经初始化,则直接返回结果
                result = mInitialized.get(component);
            }
            return (T) result;
        } finally {
            Trace.endSection();
        }
    }
}

总结


目前App Startup还很简单,没什么卵用。