写点什么

Android 启动优化: JetPack App Startup 使用及源码浅析

  • 2021 年 11 月 08 日
  • 本文字数:4134 字

    阅读完需:约 14 分钟

3 override fun onCreate(): Boolean {


4 Log.d(TAG, "XXSDKProvider create()")


5 XXSDK.init()


6 return true


7 }


8


9 .....


10}


同时,这里给做启动优化的同学提供了一种思路。打开你的 Apk,看一下 AndroidManiest 里面有多少 provider,看一下是否有这样的骚操作。如果有,改一下,说不定启动优化,一下子就减少了 100 多 毫秒。


接下来,我们来看一下 AppStartUp 怎么使用


AppStartUp 基本使用


========================================================================


简单来说,分为三步


  1. gradle 文件引入 App Startup 库。

  2. 自定义一个用于初始化的 Initializer。

  3. 将自定义 Initializer 配置到 AndroidManifest.xml 当中。


第一步,在 build.gradle 文件添加依赖


1dependencies {


2 implementation "androidx.startup:startup-runtime:1.0.0"


3}


第二步:自定义实现 Initializer 类


主要有两个方法


  1. T create(@NonNull Context context) 初始化一个组件,返回给 Application

  2. List<class<? extends="" initializer>> dependencies() 当前的 Initializer 依赖于那些 Initializers,通过这个可以确定先后启动的


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


顺序


我们以官方的例子来讲解


1// Initializes WorkManager.


2class WorkManagerInitializer : Initializer<WorkManager> {


3 override fun create(context: Context): WorkManager {


4 val configuration = Configuration.Builder().build()


5 WorkManager.initialize(context, configuration)


6 return WorkManager.getInstance(context)


7 }


8 override fun dependencies(): List<Class<out Initializer<*>>> {


9 // No dependencies on other libraries.


10 return emptyList()


11 }


12}


WorkManagerInitializer 返回一个 WorkManager,它不需要依赖于其他的 Initializer,直接返回 emptyList() 即可。


如果需要依赖其他的 Initializer,重写 dependencies 方法,返回即可。如下面的 ExampleLoggerInitializer 依赖于 WorkManagerInitializer


1// Initializes ExampleLogger.


2class ExampleLoggerInitializer : Initializer<ExampleLogger> {


3 override fun create(context: Context): ExampleLogger {


4 // WorkManager.getInstance() is non-null only after


5 // WorkManager is initialized.


6 return ExampleLogger(WorkManager.getInstance(context))


7 }


8


9 override fun dependencies(): List<Class<out Initializer<*>>> {


10 // Defines a dependency on WorkManagerInitializer so it can be


11 // initialized after WorkManager is initialized.


12 return listOf(WorkManagerInitializer::class.java)


13 }


14}


15


16class ExampleLogger(val workManager: WorkManager){


17


18}


第三步:在 AndroidManifest 里面配置自定义的 InitializationProvider


1<provider


2 android:name="androidx.startup.InitializationProvider"


3 android:authorities="${applicationId}.androidx-startup"


4 android:exported="false"


5 tools:node="merge">


7 <meta-data android:name="com.xj.anchortask.appstartup.ExampleLoggerInitializer"


8 android:value="androidx.startup" />


9</provider>


它是有固定格式的,配置者只需要配置 meta-data 中的 name 即可。 android:name=“com.xj.anchortask.appstartup.ExampleLoggerInitializer” 这里的 name 是我们自定义的 Initializer 全路径。


程序运行跑起来,可以看到以下输出结果,符合我们的预期


2021-04-17 17:48:42.049 28059-28059/com.xj.anchortask I/AnchorTaskApplication: attachBaseContext:


2021-04-17 17:48:42.077 28059-28059/com.xj.anchortask I/AnchorTaskApplication: create: WorkManagerInitializer init


2021-04-17 17:48:42.077 28059-28059/com.xj.anchortask I/AnchorTaskApplication: create: ExampleLoggerInitializer init


2021-04-17 17:48:42.084 28059-28059/com.xj.anchortask I/AnchorTaskApplication: onCreate:


AppStartUp 进阶使用


========================================================================


手动初始化




上面我们讲解了 AppStartUp 的基本使用步骤,如果我们不想在 Application onCreate 之前执行我们的 ExampleLoggerInitializer,要怎么使用呢?


其实很简单,


  1. 第一步,在 AndroidManifest InitializationProvider 中移除 移除 <meta-data 标签

  2. 在代码中调用 AppInitializer initializeComponent 方法初始化


1<provider


2 android:name="androidx.startup.InitializationProvider"


3 android:authorities="${applicationId}.androidx-startup"


4 android:exported="false"


5 tools:node="merge">


6


7</provider>


1AppInitializer.getInstance(context).initializeComponent(ExampleLoggerInitializer::class.java)


App start up 源码分析


我们首先来看一下他的结构,只有简单的几个类



Initializer 这个接口就没有必要说了,很简单,只有两个方法。


InitializationProvider 继承了 ContentProvider,借助了 ContentProvider 会在 Application onCreate 之前执行的特点。来执行一些初始化操作。


1public final class InitializationProvider extends ContentProvider {


2 @Override


3 public boolean onCreate() {


4 Context context = getContext();


5 if (context != null) {


6 AppInitializer.getInstance(context).discoverAndInitialize();


7 } else {


8 throw new StartupException("Context cannot be null");


9 }


10 return true;


11 }


12


13 ----


14


15}


我们可以看到在 onCreate 方法中调用 AppInitializer discoverAndInitialize 方法进行初始化。


  1. 找到 AndroidManifest InitializationProvider 下的 meta 便签

  2. 判断 meta 便签下 value 的值是不是 androidx.startup

  3. 判断是不是实现 Initializer 接口,是的话,执行 doInitialize 方法


1void discoverAndInitialize() {


2 try {


3 Trace.beginSection(SECTION_NAME);


4 ComponentName provider = new ComponentName(mContext.getPackageName(),


5 InitializationProvider.class.getName());


6 ProviderInfo providerInfo = mContext.getPackageManager()


7 .getProviderInfo(provider, GET_META_DATA);


8 Bundle metadata = providerInfo.metaData;


9 String startup = mContext.getString(R.string.androidx_startup);


10 // 找到 metadata 标签


11 if (metadata != null) {


12 Set<Class<?>> initializing = new HashSet<>();


13 Set<String> keys = metadata.keySet();


14 for (String key : keys) {


15 String value = metadata.getString(key, null);


16 // 判断 value 的值是不是 androidx.startup


17 // 判断是不是实现了 Initializer 接口,是的话,反射初始化


18 if (startup.equals(value)) {


19 Class<?> clazz = Class.forName(key);


20 if (Initializer.class.isAssignableFrom(clazz)) {


21 Class<? extends Initializer<?>> component =


22 (Class<? extends Initializer<?>>) clazz;


23 mDiscovered.add(component);


24 if (StartupLogger.DEBUG) {


25 StartupLogger.i(String.format("Discovered %s", key));


26 }


27 doInitialize(component, initializing);


28 }


29 }


30 }


31 }


32 } catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {


33 throw new StartupException(exception);


34 } finally {


35 Trace.endSection();


36 }


37}


doInitialize 方法


1<T> T doInitialize(


2 @NonNull Class<? extends Initializer<?>> component,


3 @NonNull Set<Class<?>> initializing) {


4 synchronized (sLock) {


5 boolean isTracingEnabled = Trace.isEnabled();


6 try {


7 if (isTracingEnabled) {


8 // Use the simpleName here because section names would get too big otherwise.


9 Trace.beginSection(component.getSimpleName());


10 }


11 if (initializing.contains(component)) {


12 String message = String.format(


13 "Cannot initialize %s. Cycle detected.", component.getName()


14 );


15 throw new IllegalStateException(message);


16 }


17 Object result;


18 if (!mInitialized.containsKey(component)) {


19 initializing.add(component);


20 try {


21 Object instance = component.getDeclaredConstructor().newInstance();


22 Initializer<?> initializer = (Initializer<?>) instance;


23 List<Class<? extends Initializer<?>>> dependencies =


24 initializer.dependencies();


25


26 if (!dependencies.isEmpty()) {


27 for (Class<? extends Initializer<?>> clazz : dependencies) {


28 if (!mInitialized.containsKey(clazz)) {


29 doInitialize(clazz, initializing);


30 }

评论

发布
暂无评论
Android 启动优化: JetPack App Startup 使用及源码浅析