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

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”>

6

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

8 android:value=“androidx.startup” />

9

它是有固定格式的,配置者只需要配置 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

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

App start up 源码分析

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

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

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 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 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 }

31 }

32 }

33 if (StartupLogger.DEBUG) {

34 StartupLogger.i(String.format(“Initializing %s”, component.getName()));

35 }

36 result = initializer.create(mContext);

37 if (StartupLogger.DEBUG) {

38 StartupLogger.i(String.format(“Initialized %s”, component.getName()));

39 }

40 initializing.remove(component);

41 mInitialized.put(component, result);

42 } catch (Throwable throwable) {

43 throw new StartupException(throwable);

44 }

45 } else {

46 result = mInitialized.get(component);

47 }

48 return (T) result;

49 } finally {

50 Trace.endSection();

51 }

52 }

53}

可以看到在执行初始化的时候,先判断了是否有依赖项,有的话先执行依赖项的初始化

小结

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

  • App start up,我觉得他的设计初衷应该是为了收拢 ContentProvider,实际上对启动优化的帮助不是很大。

  • 如果你的项目都是同步初始化的话,并且使用到了多个ContentProvider,App Startup可能有一定的优化空间,毕竟统一到了一个ContentProvider中,同时支持了简单的顺序依赖。

尾声

最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

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

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
Android 启动优化: JetPack App Startup 使用及源码浅析

QEevEIJ-1644027873175)]

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
[外链图片转存中…(img-J7i0DN1C-1644027873176)]

上一篇:排序


下一篇:Tensorflow不同版本要求与CUDA及CUDNN版本对应关系