即学即用Android Jetpack - Startup

技术不止,文章有料,加 JiuXinDev 入群,Android 搬砖路上不孤单

前言

即学即用 Android Jetpack 系列Blog的目的是通过学习 Android Jetpack 完成一个简单的Demo,本文是即学即用 Android Jetpack 系列Blog的第七篇。

由于 Android Jetpack 在前一时间里更新了新的库 Startup、Hit 和 Page 3,那么《即学即用Android Jetpack》系列文章就需要加入新的内容了。

在接下来的几周里,除了增加新的 Android Jetpack 文章以外,我还会对之前的入门 Android Jetpack 中的项目 【Hoo】 中所使用的旧的 Jetpack 库进行升级。

Jetpack系列文章🚀:

第一篇:《即学即用Android Jetpack - Navigation》
第二篇:《即学即用Android Jetpack - Data Binding》
第三篇:《即学即用Android Jetpack - ViewModel & LiveData》
第四篇:《即学即用Android Jetpack - Room》
第五篇:《即学即用Android Jetpack - Paging》
第六篇:《即学即用Android Jetpack - WorkManger》
第七篇:《即学即用Android Jetpack - Startup》
项目总结篇:《学习Android Jetpack? 实战和教程这里全都有!》

目录

目录

一、介绍

从库名 StartUp 来看,不难猜出,它是一个跟启动相关的库。

我们先从背景讲起,一些第三方库需要Activity启动之前去进行初始化,比如说我们之前谈过的 WorkManager 和 常见的数据库相关的库,不可能说进入到 Activity 的时候我再去初始化,因为这种初始化可能会比较耗时,给用户带来的体验也比较差。

我们再来谈一下常用的库初始化的方法:

  1. 自定义 Application,并在 Application#onCreate() 中进行初始化。优点也是它的缺点,需要手动调用,但是能自己控制调用时机。
  2. 自定义 ContentProvider,并在 ContentProvider#onCreate() 中进行初始化。优点是自动调用,降低开发者的学习成本,缺点是 ContentProvider 是一个相对来说比较重的操作,初始化一个 ContentProvider 带来的开销比较小,如果大家开发的第三方库都使用这种操作呢?结果可想而知,延长我们 App 的启动时间。

借用郭神《Jetpack新成员,App Startup一篇就懂》里的空 ContentProvider 初始化的时候的开销:

ContentProvider消耗

有了上面的基础,我们就可以讲 StartUp 的使用了,StartUp 采用的是第二种方式,它的目的是仅仅是为了使用一个 ConttentProvider 来初始化那些需要初始化的库。

图片来自《AndroidX: App Startup》,不使用 Startup 的时候:

多个ContentProvider

使用 Startup 的时候:

Startup的使用场景

其实我感觉真正的事实并不是这样的,而是:

真实场景

Startup 并不能解决已经使用 ContentProvider 进行初始化的第三方库,而对于没有使用 ContentProvider 初始化,并且需要初始化的库,我可以只选择一个 ContentProvider 进行初始化,或者在 Application 中的 onCreate() 方法中进行初始化,还可以省去引入一个库和创建 ContentProvider 的开销。

不过既然谷歌创建了 Startup,总归是有用处的,学习方式仍然推荐官方文档:

官方文档:https://developer.android.com/topic/libraries/app-startup

二、使用

Startup 的使用方式很简单。

第一步 添加依赖

dependencies {
    implementation "androidx.startup:startup-runtime:1.0.0-alpha02"
}

第二步 实现Initializer

实现 Initializer 需要实现其中的两个方法,我们先以 Room 数据库初始化为例:

class RoomInitializer : Initializer<AppDataBase> {
    override fun create(context: Context): AppDataBase {
        return AppDataBase.getInstance(context)
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return emptyList()
    }
}

需要实现两个方法:

  • onCreate:在这个方法执行需要初始化的动作,比如在上面的 RoomInitializer 中的 AppDataBase.getInstance(context),我会进行数据的初始化,具体的代码我就不放了。
  • dependencies:比如说我当前库 A 依赖库 B,B 初始化成功以后才能进行 A 的初始化,这个时候我就需要返回包含 B 的 InitializerClassList

我们这里再创建一个 PushInitializer,假设它必须再 Room 初始化完成以后它才能进行初始化:

class PushInitializer  :Initializer<PushSdk>{
    override fun create(context: Context): PushSdk {
        val push = PushSdk("MPush")
        push.registerPush()
        return push
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return listOf(RoomInitializer::class.java)
    }
}

/**
 * 这是一个伪造的推送类 PushSdk
 */
data class PushSdk(val name:String){
    fun registerPush(){
        print("Hello,i'm registering push")
    }
}

是不是感觉很简单。

这里谈一下我在官方文档遇到的一个坑,我看到官方文档上可以建 WorkManager 的 Initializer,代码是这样的:

// Initializes WorkManager.
class WorkManagerInitializer : Initializer<WorkManager> {
    override fun create(context: Context): WorkManager {
        val configuration = Configuration.Builder().build()
        WorkManager.initialize(context, configuration)
        return WorkManager.getInstance()
    }
    override fun dependencies(): List<Class<out Initializer<*>>> {
        // No dependencies on other libraries.
        return emptyList()
    }
}

如果你这样写,恭喜你,接下来,你会收到一个这样的闪退:

java.lang.RuntimeException: Unable to get provider androidx.startup.InitializationProvider: androidx.startup.StartupException: androidx.startup.StartupException: java.lang.IllegalStateException: WorkManager is already initialized.

意思是我们的 WorkManager 已经初始化过了,不需要再初始化了。

因为 WorkManagerInitializer 这个类继承了 ContentProvider,它已经在 ContentProvider#onCreate() 方法中对 WorkManager 进行了初始化,我们再在 Startup 进行初始化就是多此一举。

第三步 在AndroidManifest文件中声明InitializationProvider

毕竟 Startup 采用的是 ContentProvider 的方式进行初始化,所以在 AndroidManifest 初始化是避免不了的。

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="com.joe.jetpackdemo.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <!-- This entry makes ExampleLoggerInitializer discoverable. -->
    <meta-data
        android:name="com.joe.jetpackdemo.common.start.PushInitializer"
        android:value="androidx.startup" />
</provider>

我们需要注意的是 meta-data 标签,需要初始化的 Initializer 都会被声明成 meta-data,这里有一点可以简化,在上面一步中,我们声明了 PushInitializerRoomInitializerPushInitializer 是依赖于 RoomInitializer 的,被依赖的 RoomInitializer 可以不用申明。

第四步 使用懒加载

你可能会提出这样的一个问题,虽然在 provider 标签中声明了 Initializer,但是因为某些原因,可不可以在 InitializationProvider 初始化的时候不会去进行相关库的初始化,而是在后面的某个时机手动初始化?

这种懒加载的方式在 Startup 中是存在的,方法是在 meta-data 标签中加入 tools:node="remove"

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="com.joe.jetpackdemo.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <!-- This entry makes ExampleLoggerInitializer discoverable. -->
    <meta-data
        android:name="com.joe.jetpackdemo.common.start.PushInitializer"
        android:value="androidx.startup"
        tools:node="remove"/>
</provider>

之后在你想进行初始化的地方调用:

AppInitializer.getInstance(context)
    .initializeComponent(PushInitializer::class.java)

三、总结

目前看来,Stratup 的并没有特别大的优势,也许是帮我们简化了依赖逻辑?

目瞪口呆

如果你有更好的见解,欢迎在下方评论留言。

引用文章:

《AndroidX: App Startup》
《Jetpack新成员,App Startup一篇就懂》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • 通过这篇文章你将学习到以下内容:App Startup 是什么?App Startup 为我们解决了什么问题?为什...
    灬佐手边阅读 555评论 0 1
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,513评论 16 22
  • 创业是很多人的梦想,多少人为了理想和不甘选择了创业来实现自我价值,我就是其中一个。 创业后,我由女人变成了超人,什...
    亦宝宝阅读 1,803评论 4 1
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,559评论 0 11
  • 可爱进取,孤独成精。努力飞翔,天堂翱翔。战争美好,孤独进取。胆大飞翔,成就辉煌。努力进取,遥望,和谐家园。可爱游走...
    赵原野阅读 2,723评论 1 1