最近jetpack又有新成员了–App Startup。刚开始看到这个字面理解就是和app启动相关的。我们来看一下官方给出的解释: 看不懂?没关系,大致意思就是:提供了在 App 启动时初始化组件简单、高效的方法,无论是 library 开发人员还是 App 开发人员都可以使用 App Startup 显示的设置初始化顺序,简单的说就是 App Startup 提供了一个 ContentProvider 来运行所有依赖项的初始化,避免每个第三方库单独使用 ContentProvider 进行初始化,从而提高了应用的程序的启动速度。
App 启动运行时会初始化一些逻辑,它们为了方便开发者使用,避免开发者手动调用,使用 ContentProvider 进行初始化,官方还提供了WorkManager的启动方式的示例,说明了它是如何通过WorkManagerInitializer 启动的。在AndroidManifest.xml文件中添加如下配置: 我们载来看看WorkManagerInitializer的源码
public class WorkManagerInitializer extends ContentProvider { @Override public boolean onCreate() { // Initialize WorkManager with the default configuration. WorkManager.initialize(getContext(), new Configuration.Builder().build()); return true; } .... }关键方法就是onCreate()方法。
可以看到当前类继承了ContentProvider ,都知道它是android跨进程通信的一种方式在onCreate()中,进行了WorkManager的初始化操作。知道了以上两点,我们自己也可以模仿WorkManagerInitializer ,看看具体操作。
代码如下:
public class Lib1 extends ContentProvider { @Override public boolean onCreate() { Log.e("Lib1初始化》》》》》》》","1111111111111"); return true; } }代码如下:
public class Lib2 extends ContentProvider { @Override public boolean onCreate() { Log.e("Lib2初始化》》》》》》》","2222222222222"); return true; } }启动app,运行结果如下: 那么,如果我现在有这样一个需求:Lib1要依赖于Lib2。也就是说,只有当Lib2启动初始化完成以后,才初始化Lib,那该如何操作呢?,当然,Android Startup就是为此而存在的。
为了解决上面的问题,Startup为我们提供了Initializer这个接口,源码如下:
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(); } onCreate()方法中就是需要我们需要初始化的地方dependencies()方法,添加我们需要依赖的启动项。比如A需要依赖B,那么就可以在该方法中进行配置B。它的启动需要依赖Lib2的启动。
它不需要依赖,在dependencies()返回空的list集合。
我们只配置了InitializerLib1,因为我们在它的dependencies()方法中依赖了InitializerLib2,所以就不需要配置了。看到这里,我们还是要看一下InitializationProvider
public final class InitializationProvider extends ContentProvider { @Override public boolean onCreate() { Context context = getContext(); if (context != null) { AppInitializer.getInstance(context).discoverAndInitialize(); } else { throw new StartupException("Context cannot be null"); } return true; } ... }只需要关注AppInitializer.getInstance(context).discoverAndInitialize()。
以上代码,大致分为三个步骤:
第一步:找到meta-data的配置项第二步:得到Initializer组件,这里对应InitializerLib1第二步:开始初始化组件以上代码,大致也可分为四个步骤:
第一步:实例化该组件第二步:得到当前组件下的所有依赖组件第三步:递归依赖的组件,继续执行doInitialize()方法第四步:调用组件的onCreate()方法其实在第三步我们就可以发现,不需要配置依赖组件的关键所在。
没运行前,我们理想中的结果,应该是先打印Lib2的日志,再打印Lib1的日志,看看如何。 是不是很炫酷!!!
以上基本上介绍完startup的用法。其实,官网上提供了两种初始化组件的方法
自动初始化:在AndroidManifest.xml中配置启动手动初始化(懒加载):代码启动第一种方式,上面的代码已经介绍过了,好处就是,不需要代码管理,自动执行。 第二种方式,我们也可以尝试一下:
AppInitializer.getInstance(getApplicationContext()).initializeComponent(InitializerLib1.class);一行代码搞定,我们看一下原理:
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) { return doInitialize(component, new HashSet<Class<?>>()); }其实,最终还是无法逃离 doInitialize() 方法。这里就不做多余的复述了。 这种启动方式,操作上其实也简单,另外还有一个好处就是,可以加快app的启动速度,因为我们不需要在启动的时候就做耗时的初始化操作。 推荐使用!!!