FastStartup icon indicating copy to clipboard operation
FastStartup copied to clipboard

FastStartup 有向无环图启动框架

FastStartup

FastStartup是一个组件启动框架,旨在帮助开发人员能够简单、高效地进行各种组件的初始化操作。
【更新记录】

特点

简单、高效、支持解藕。 没有过多的启动配置方式,只为提供简单的使用体验。 全程无反射,无IO操作,能给您提供最快的启动速度。

使用它你能得到什么?

  1. 全程无反射,无IO操作,提供最快的启动速度
  2. 组件只需要关注自己依赖的其他组件,自动维护初始化顺序
  3. 组件支持配置运行在UI线程和非UI线程
  4. 支持UI线程等待操作,可以让UI线程阻塞到必要组件初始化完成,而必要组件可以运行在任意线程
  5. 支持组件初始化参数配置,您可以创建一个任意形式配置信息,该配置信息将贯穿所有组件的初始化操作
  6. 支持解藕,采用接口进行依赖管理,避免组件间的强依赖,让您的工程更加简洁
  7. 支持组件自动注入,提供AOP方案,让您无需再处理每一个组件,只需要一个注解就可以自动进行初始化,实现依赖即配置
  8. 支持组件完成回调,提供了三种回调,分别为每个组件初始化完成的回调、UI线程任务完成的回调、所有任务完成的回调
  9. 支持组件初始化耗时统计
  10. 支持依赖缺失检测和依赖循环依赖检测
  11. 支持隐私模式启动,自动根据组件依赖关系和是否需要隐私模式启动进行初始化处理,能够在隐私权限授予后再次调用自动执行剩余任务
  12. 支持组件依赖关系打印

使用方式

1. 基础配置

在项目工程目录下build.gradle中添加依赖

dependencies {
    //请使用最新版本
    implementation "io.github.wizzxu:fast-startup:0.0.2"
}

2. 组件初始化

Application onCreat()方法中进行初始化和启动

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        FastStartup.init().start()
    }
}

init()方法中需要传入配置信息

简单配置
FastStartup.init(StartupConfig(application = this, BuildConfig.DEBUG)).start(listOf(A(), B()))
详细配置
FastStartup.init(
    StartupConfig.Builder()
        .setApplication(this)                    //application (默认为空)
        .setIsDebug(BuildConfig.DEBUG)           //是否是debug (默认为空)
        .setParams(mapOf("key" to "value"))      //通用配置参数 (默认为空)
        .setEnableTimeStatistics(true)           //是否打印每一个startup启动耗时(需要日志级别Log.ERROR以下,默认不分析耗时)
        .setLogLevel(Log.DEBUG)                  //组件内打印的日志级别 (默认不打印)
        .setStartupCompleteListener(object : StartupCompleteListener {
            override fun startupComplete(startup: IStartup<*>) {
                SLog.d("FastStartup", "目前完成的startup为:" + startup::class.java.simpleName)
            }

        })
        .setUIStartupCompleteListener(object : UIStartupCompleteListener {
            override fun startupComplete() {
                SLog.d("FastStartup", "所有运行在UI线程和需要UI线程等待的Startup已经全部完成")
            }
        })
        .setAllStartupCompleteListener(object : AllStartupCompleteListener {
            override fun startupComplete() {
                SLog.d("FastStartup", "所有Startup已经全部完成")
            }
        })
        .build()
).start(listOf(A(), B()))

start()方法中需要传入组件列表信息 组件需要实现IStartup接口,具体详细用法,请查看IStartup

class A : IStartup<String> {
    override fun start(context: Context?, isDebug: Boolean?, any: Any?): String? {
        return null
    }
}

class B : IStartup<String> {
    override fun start(context: Context?, isDebug: Boolean?, any: Any?): String? {
        return null
    }

    override fun runOnUIThread(): Boolean {
        return true
    }

    override fun dependencies(): List<Class<out IStartup<*>>>? {
        return listOf(A::class.java)
    }
}

3. 获取组件实例对象获取获取组件初始化返回的结果

获取组件实例对象
val class1:A? = FastStartup.getStartup(A::class.java)
val class2:IA<*>? = FastStartup.getStartup(A::class.java)
val class3:IA<*>? = FastStartup.getStartup(IA::class.java)

获取组件`start`方法返回的结果
Log.d("TestGetResult", "${FastStartup.getStartupResult(A::class.java)}")
Log.d("TestGetResult", "${FastStartup.getStartupResult(IA::class.java)}")

至此,您已经可以愉快的使用FastStartup

依赖环检测和缺失检测

在FastStartup启动的时候会自动进行依赖环检测和缺失检测 如果依赖有环,会抛出异常并会打印如下信息 dep_pic_1

如果依赖有缺失,会打印如下消息 dep_pic_2

耗时统计

cost_time

依赖关系打印

dep_list_pic

FastStartup 高级用法 解藕、AOP、隐私模式

1. 解藕

有的时候,我们组件是解藕的,对外提供接口,靠接口来进行依赖和调用,这种方式在FastStartup要怎么使用呢?

1. 组件工程添加IStartup组件依赖

dependencies {
    //请使用最新版本
    implementation "io.github.wizzxu:fast-startup-api:0.0.2"
}

组件接口必须直接继承IStartup

interface IA<T> : IStartup<T>
class A : IA<String> {
    override fun start(context: Context?, isDebug: Boolean?, any: Any?): String? {
        return null
    }

    override fun dependencies(): List<Class<out IStartup<*>>>? {
        return null
    }
}

class B : IStartup<String> {
    override fun start(context: Context?, isDebug: Boolean?, any: Any?): String? {
        return null
    }

    override fun dependencies(): List<Class<out IStartup<*>>>? {
        return listOf(IA::class.java)
    }
}

这样在B组件中就可以依赖A组件的接口IA完成依赖关系。从而B组件不必直接依赖A组件,只需要依赖A组件的接口所在工程就可以完成依赖。 但是FastStartup调用start方法的时候必须添加所有组件的实现类

FastStartup.init(StartupConfig(application = this, BuildConfig.DEBUG)).start(listOf(A(), B()))

2. AOP方式进行组件初始化

如果您的组件分布在不同仓库,而您不想在初始化的时候去统一添加这些组件,那么您可以通过使用AOP插件来实现。 AOP方案的实现基于Booster实现

1. 配置

在项目根目录下build.gradle中添加依赖

buildscript {
    ext.kotlin_version = "1.5.31"
    ext.booster_version = '4.0.0'
    ext.fast_startup_transformer = '0.0.1'//请使用最新版本

    dependencies {
        // 添加booster插件
        classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
        // 添加fast-startup-transformer依赖
        classpath "io.github.wizzxu:fast-startup-transformer:$fast_startup_transformer"
    }
}

在项目目录下build.gradle中添加插件

plugins {
    id 'com.didiglobal.booster'
}

2. 组件添加注解 @AFastStartup

@AFastStartup注解在"io.github.wizzxu:fast-startup-api:0.0.1"库中

interface IA<T> : IStartup<T>
@AFastStartup
class A : IA<String> {
    override fun start(context: Context?, isDebug: Boolean?, any: Any?): String? {
        return null
    }

    override fun dependencies(): List<Class<out IStartup<*>>>? {
        return null
    }
}
@AFastStartup
class B : IStartup<String> {
    override fun start(context: Context?, isDebug: Boolean?, any: Any?): String? {
        return null
    }

    override fun runOnUIThread(): Boolean {
        return true
    }

    override fun dependencies(): List<Class<out IStartup<*>>>? {
        return listOf(IA::class.java)
    }
}

配置完毕,现在您就可以摆脱手动添加组件啦,在启动的时候

FastStartup.init(StartupConfig(application = this, BuildConfig.DEBUG)).start())

start()方法里面不需要传入任何内容,就可以自动注入组件啦

3. 隐私模式启动

1. Startup创建的时候重写needPrivacyAgree()

override fun needPrivacyAgree(): Boolean {
    return true
}

2. 授予隐私权限之后再次调用

FastStartup.init(StartupConfig(application = this, BuildConfig.DEBUG)).start(listOf(A(), B()))
// 设置授予隐私权限并再次执行任务
FastStartup.setPrivacyAgree(true).reStart()

注意: 各种监听器在一次隐私权限未授予的任务执行完毕之后,会销毁。授予隐私权限后需要重新设置任务监听器

FastStartup.setPrivacyAgree(true)
.registerAllStartupCompleteListener(object :
    AllStartupCompleteListener {
    override fun startupComplete() {
        SLog.e("registerAllStartupCompleteListener")
    }
}).registerUIStartupCompleteListener(object : UIStartupCompleteListener {
    override fun startupComplete() {
        SLog.e("registerUIStartupCompleteListener")

    }
}).registerStartupCompleteListener(object : StartupCompleteListener {
    override fun startupComplete(startup: IStartup<*>) {
        SLog.e("registerStartupCompleteListener:${startup.javaClass.simpleName}")
    }

}).reStart()

感谢

在开发的过程中也是参考了和借鉴了部分其他开源库,在此特感谢各位大佬。

【Booster】 一个优秀的AOP解决方案
【android-startup】 一个优秀的Android启动方案,本组件的很多实现细节有参考android-startup,但是设计理念有些不同,并且提供了解藕方案、ASM插桩自动注册方案,去除了android-startup里面很多复杂的配置方式
【AndroidStartup】 一个优秀的Android启动方案,虾佬的杰作,换了种思路实现了Startup,添加DSL方式配置,也非常值得学习

License

请查看LICENSE