• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

我为何弃用Jetpack的App-Startup

android 搞代码 3年前 (2022-03-02) 22次浏览 已收录 0个评论
文章目录[隐藏]

前言

最近Jetpack又增加了新成员App Startup,官网申明这是一个在Android利用启动时,针对初始化组件进行优化的依赖库。自己第一次听到后非常高兴,因为本人负责的我的项目在启动时须要初始化的货色切实是太多,而且有点横七竖八,都耦合在一起了。对于能够异步初始化的组件也没有进行异步解决,而对于曾经解决过的异步组件它们之间的依赖关系或者多个异步之后的对立逻辑解决也没有一个很好的对立标准。所以针对这种状况早就想找个计划来优化了,这次终于等到了App Startup

然而,当我元气满满的去查看官网文档时,并没有找到料想中的后果。官网文档中只提到了能够通过一个ContentProvider来对立治理须要初始化的组件,同时通过dependencies()办法解决组件间初始化的依赖程序,而后呢?没了?等等官网你是不是漏了什么?

异步解决呢?尽管咱们能够在create()办法中手动创立子线程进行异步工作,但一个异步工作依赖另一个异步工作又该如何解决呢?多个异步工作实现之后,对立逻辑解决又在哪里呢?依赖工作实现后的回调又在哪里?亦或者是依赖工作实现后的告诉?

我有点不置信,所以又去查看了App Startup的源码,源码很简略,也就几个文件,最初发现的确只反对下面的那几个性能。

如果你的我的项目都是同步初始化的话,并且应用到了多个ContentProviderApp Startup可能有肯定的优化空间,毕竟对立到了一个ContentProvider中,同时反对了简略的程序依赖。

值得一提的是,App Startup中只提供了应用反射来获取初始化的组件实例,这对于一些没有过多依赖的初始化我的项目来说,自觉应用App Startup来优化是否会对启动速度进一步造成影响呢?

所以细想了一下,不禁让我想起了三国时的一个名词:鸡肋。食之无味,弃之可惜。

但最终我还是决定放弃应用它。

放弃之后有点不甘心,可能更多的是它没有解决我以后的我的项目场景。都剖析了这么多,源码都看了,总不能大功告成吧,所以本人咬咬牙再补充一点呗。

所以保持一下,就有了上面这个库,App Startup的进阶版Android Startup

Android Startup

Android Startup提供一种在利用启动时可能更加简略、高效的形式来初始化组件。开发人员能够应用Android Startup来简化启动序列,并显式地设置初始化程序与组件之间的依赖关系。
与此同时,Android Startup反对同步与异步期待,并通过有向无环图拓扑排序的形式来保障外部依赖组件的初始化程序。

因为Android Startup是基于App Startup进行的扩大,所以它的应用形式与App Startup有点相似,该有的性能基本上都有,同时额定还附加其它性能。

上面是一张与google的App Startup性能比照的表格。

指标 App Startup Android Startup
手动配置
主动配置
依赖反对
闭环解决
线程管制
异步期待
依赖回调
拓扑优化

上面简略介绍一下Android Startup的应用。

增加依赖

将上面的依赖增加到build.gradle文件中:

dependencies {
    implementation 'com.rousetime.android:android-startup:1.0.1'
}

依赖版本的更新信息: Release

疾速应用

android-startup提供了两种应用形式,在应用之前须要先定义初始化的组件。

定义初始化的组件

每一个初始化的组件都须要实现AndroidStartup<T>抽象类,它实现了Startup<T>接口,它次要有以下四个形象办法:

  • callCreateOnMainThread(): Boolean用来管制create()办法调时所在的线程,返回true代表在主线程执行。
  • waitOnMainThread(): Boolean用来管制以后初始化的组件是否须要在主线程进行期待其实现。如果返回true,将在主线程期待,并且阻塞主线程。
  • create(): T?组件初始化办法,执行须要解决的初始化逻辑,反对返回一个T类型的实例。
  • dependencies(): List<Class<out Startup<*>>>?返回Startup<*>类型的list汇合。用来示意以后组件在执行之前须要依赖的组件。

例如,上面定义一个SampleFirstStartup类来实现AndroidStartup<String>抽象类:

class SampleFirstStartup : AndroidStartup<String>() {
 
    override fun callCreateOnMainThread(): Boolean = true
 
    override fun waitOnMainThread(): Boolean = false
 
    override fun create(context: Context): String? {
        // todo something
        return this.javaClass.simpleName
    }
 
    override fun dependencies(): List<Class<out Startup<*>>>? {
        return null
    }
 
}

因为SampleFirstStartup在执行之前不须要依赖其它组件,所以它的dependencies()办法能够返回空,同时它会在主线程中执行。

留神:️尽管waitOnMainThread()返回了false,但因为它是在主线程中执行,而主线程默认是阻塞的,所以callCreateOnMainThread()返回true时,该办法设置将生效。

假如你还须要定义SampleSecondStartup,它依赖于SampleFirstStartup。这意味着在执行SampleSecondStartup之前SampleFirstStartup必须先执行结束。

class SampleSecondStartup : AndroidStartup<Boolean>() {
 
    override fun callCreateOnMainThread(): Boolean = false
 
    override fun waitOnMainThread(): Boolean = true
 
    override fun create(context: Context): Boolean {
        // 模拟执行耗时
        Thread.sleep(5000)
        return true
    }
 
    override fun dependencies(): List<Class<out Startup<*>>>? {
        return listOf(SampleFirstStartup::class.java)
    }
 
}

dependencies()办法中返回了SampleFirstStartup,所以它能保障SampleFirstStartup优先执行结束。
它会在子线程中执行,但因为waitOnMainThread()返回了true,所以主线程会阻塞期待直到它执行结束。

例如,你还定义了SampleThirdStartup与SampleFourthStartup

Manifest中主动配置

第一种初始化办法是在Manifest中进行主动配置。

在Android Startup中提供了StartupProvider类,它是一个非凡的content provider,提供自动识别在manifest中配置的初始化组件。
为了让其可能自动识别,须要在StartupProvider中定义<meta-data>标签。其中的name为定义的组件类,value的值对应为android.startup

<provider
    android:name="com.rousetime.android_startup.provider.StartupProvider"
    android:authorities="${applicationId}.android_startup"
    android:exported="false">
 
    <meta-data
         android:name="com.rousetime.sample.startup.SampleFourthStartup"
        android:value="android.startup" />
 
</provider>

你不须要将SampleFirstStartupSampleSecondStartupSampleThirdStartup增加到<meta-data>标签中。这是因为在SampleFourthStartup中,它的dependencies()中依赖了这些组件。StartupProvider会自动识别曾经申明的组件中依赖的其它组件。

Application中手动配置

第二种初始化办法是在Application进行手动配置。

手动初始化须要应用到StartupManager.Builder()

例如,如下代码应用StartupManager.Builder()进行初始化配置。

class SampleApplication : Application() {
 
    override fun onCreate() {
        super.onCreate()
        StartupManager.Builder()
            .addStartup(SampleFirstStartup())
            .addStartup(SampleSecondStartup())
            .addStartup(SampleThirdStartup())
            .addStartup(SampleFourthStartup())
            .build(this)
            .start()
            .await()
    }
}

如果你开启了日志输入,而后运行我的项目之后,将会在控制台中输入通过拓扑排序优化之后的初始化组件的执行程序。

 D/StartupTrack: TopologySort result: 
    ================================================ ordering start ================================================
    order [0] Class: SampleFirstStartup => Dependencies size: 0 => callCreateOnMainThread: true => waitOnMainThread: false
    order [1] Class: SampleSecondStartup => Dependencies size: 1 => callCreateOnMainThread: false => waitOnMainThread: true
    order [2] Class: SampleThirdStartup => Dependencies size: 2 => callCreateOnMainThread: false => waitOnMainThread: false
    order [3] Class: SampleFourthStartup => Dependencies size: 3 => callCreateOnMainThread: false => waitOnMainThread: false
    ================================================ ordering end ================================================

残缺的代码实例,你能够通过查看app获取。

更多

可选配置

  • LoggerLevel: 管制Android Startup中的日志输入,可选值包含LoggerLevel.NONE, LoggerLevel.ERROR and LoggerLevel.DEBUG
  • AwaitTimeout: 管制Android Startup中主线程的超时等待时间,即阻塞的最长工夫。

Manifest中配置

应用这些配置,你须要定义一个类去实现StartupProviderConfig接口,并且实现它的对应办法。

class SampleStartupProviderConfig : StartupProviderConfig {
 
    override fun getConfig(): StartupConfig =
        StartupConfig.Builder()
            .setLoggerLevel(LoggerLevel.DEBUG)
            .setAwaitTimeout(12000L)
            .build()
}

与此同时,你还须要在manifest中进行配置StartupProviderConfig

<provider
     android:name="com.rousetime.android_startup.provider.StartupProvider"
    android:authorities="${applicationId}.android_startup"
    android:exported="false">
 
    <meta-data
         android:name="com.rousetime.sample.startup.SampleStartupProviderConfig"
         android:value="android.startup.provider.config" />
 
</provider>

通过下面的配置,StartupProvider会主动解析SampleStartupProviderConfig

Application中配置

在Application须要借助StartupManager.Builder()进行配置。

override fun onCreate() {
    super.onCreate()
 
    val config = StartupConfig.Builder()
        .setLoggerLevel(LoggerLevel.DEBUG)
        .setAwaitTimeout(12000L)
        .build()
 
    StartupManager.Builder()
        .setConfig(config)
        ...
        .build(this)
        .start()
        .await()
}

办法

AndroidStartup

  • createExecutor(): Executor: 如果定义的组件没有运行在主线程,那么能够通过该办法进行管制运行的子线程。
  • onDependenciesCompleted(startup: Startup<*>, result: Any?): 该办法会在每一个依赖执行结束之后进行回调。

实战测试

AwesomeGithub中应用了Android Startup,优化配置的初始化工夫与组件化开发的配置注入机会,应用前与应用后工夫比照:

状态 启动页面 耗费工夫
应用前 WelcomeActivity 420ms
应用后 WelcomeActivity 333ms

AwesomeGithub

AwesomeGithub是基于Github的客户端,纯练习我的项目,反对组件化开发,反对账户明码与认证登陆。应用Kotlin语言进行开发,我的项目架构是基于JetPack&DataBinding的MVVM;我的项目中应用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等风行开源技术。

除了Android原生版本,还有基于Flutter的跨平台版本flutter_github。

如果你喜爱我的文章,你能够关注我的微信公众号:【Android补给站】或者扫描下方二维码进行关注,当然你也能够间接关注以后网站的帐号。次要区别就是微信可能更办法互动。

公众号更新不会很频繁,但一旦更新必然是纯干货。


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:我为何弃用Jetpack的App-Startup

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址