Android Jetpack架构组件之 StartUp使用详解
一、什么是StartUp
在做Android开发时,经常会调用第三方的SDK。但是SDK一般都是需要初始化的。有些时候初始化的SDK太多了,导致应用启动时间太长,体验不好。而且一般都是在Application的onCreate()初始化。可是Application的onCreate()调用时机并不是最早的。合理的做法应该是在ContentProvider进行初始化。恰好,jetpack组件的StartUp完美符合需求。
StartUp库,即应用程序启动库,提供了一种在应用程序启动时初始化组件的简单、高效的方法。开发人员和应用程序开发人员都可以使用StartUp来简化启动序列并显式设置初始化顺序。StartUp允许您定义共享单个内容提供程序的组件初始化程序,而不是为每个要初始化的组件定义单独的ContentProvider。这可以显著缩短应用程序启动时间。简单的说就是通过一个公共的
ContentProvider来集中管理需要初始化的组件,从而提高应用的启动速度。
二、如何使用StartUp
1、在build.gradle中添加所需依赖
dependencies { implementation "androidx.startup:startup-runtime:1.0.0" }
2、创建初始化入口
每一个需要初始化的组件我们需要创建一个class去实现Initializer<T>接口
class AModuleInitializer : Initializer<AModule> { override fun create(context: Context): ASdk { Log.i("xjm","AModuleInitializer create()方法执行" ) return AModule.getInstance() } override fun dependencies(): MutableList<Class<out Initializer<*>>> { Log.i("xjm","AModuleInitializer dependencies()方法执行" ) return mutableListOf() } }
只需实现两个方法:
create ()方法
包含初始化组件所需的所有操作,并返回T的实例。
dependencies()方法
返回的是一个Initializer<T>的list,这个集合当中包含了当前的Initializer<T>所依赖的其他的Initializer<T>,由此可见该方法的
作用是让我们可以控制在程序启动时的组件的初始化顺序。(即需要依赖的Initializer初始化后,才会创建自己)
两个方法执行顺序为dependencies() -> create ()
3、启动StartUp
StartUp为我们提供了两种方式来启动,一种是自动启动,一种是手动调用启动。
1.自动启动
我们只需要在AndroidManifest中对InitializationProvider添加对应声明:
声明其原理中真正使用的ContentProvider类androidx.startup.InitializationProvider
authorities要携带${applicationId}来避免与其他App产生冲突要在这个provider下声明meta-data;Startup会去找自己Provider
下声明的第一个meta-data所对应的类,来对他进行初始化,如果他声明了他有依赖项,那么他的依赖项也会被初始化。顺序寻
找meta-data对应的类并依次初始化。
声明ContentProvider类其基本原理就是依靠ContentProvider的onCreate会在应用初始化时被自动调用;
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="com.xxx.AModuleInitializer" android:value="androidx.startup" /> <meta-data android:name="com.xxx.BModuleInitializer" android:value="androidx.startup" tools:node="remove"/> </provider>
meta-data标签:
name:是Initializer的路径
value:必须为androidx.startup才可以被收集到,后续的触发是按照在Manifest中声明的顺序进行的。
依赖链声明
若存在依赖关系C -> B -> A,则只需要声明C即可,因为A和B可以通过C的dependencies()方法链式调用进行初始化。A,B,C的执行顺序为:
C的dependencies() -> B的dependencies() -> A的dependencies() -> A的create () -> B的create () -> C的create () ->
若A、B、C之间不存在依赖关系的话,则需要对每一个对应的Initializer进行声明。而A、B、C的执行顺序则与我们的声明顺序保持一致。
需要注意的是:
会使用Map mInitialized来确保每个类只会被初始化一次,而通过临时的initializing确保在依赖关系中不允许循环依赖
2.手动调用启动
(1)、声明中关闭自动初始化
tools:node=”remove”这个标签的作用是为了防止在其他引用的三方库中有对相同组件的一个初始化,保证该组件的自动初始化
真正的被关闭。
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="com.xxx.BModuleInitializer" android:value="androidx.startup" tools:node="remove"/> </provider>
关闭startup的所有组件的自动初始化,除了在<meta-data>标签上一个个添加之外,还可以统一关闭:
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" tools:node="remove"/>
(2)、在代码中进行初始化
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //手动启动初始化 AppInitializer.getInstance(this).initializeComponent(BModuleInitializer::class.java) } }
三、源代码
AppInitializer类
public final class AppInitializer { private static AppInitializer sInstance; /** * Guards app initialization. */ private static final Object sLock = new Object(); @NonNull final Map<Class<?>, Object> mInitialized; @NonNull final Context mContext; /** * Creates an instance of {@link AppInitializer} * * @param context The application context */ AppInitializer(@NonNull Context context) { mContext = context.getApplicationContext(); mInitialized = new HashMap<>(); } /** * @param context The Application {@link Context} * @return The instance of {@link AppInitializer} after initialization. */ @NonNull @SuppressWarnings("UnusedReturnValue") public static AppInitializer getInstance(@NonNull Context context) { synchronized (sLock) { if (sInstance == null) { sInstance = new AppInitializer(context); } return sInstance; } } ... }
Map<Class<?>, Object> 用map去存储已经被初始化过的组件。