Jetpack—架构组件—App Startup

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Jetpack—架构组件—App Startup

App Startup


介绍作用

image.png

这是官网的截图,大意就是 App Startup 是一种用来在 app 启动时候规范初始化数据的 library。同时使用 App Startup 可以解决我们平时滥用 ContentProvider 导致的启动变慢问题。

还有一点,App Startup 可以用于 app 开发,也可以用来进行 sdk 开发


App Startup 的优势

  1. 平时使用 ContentProvider 自动获取 ApplicationContext 的方式管理混乱,并且多个 ContentProvider 初始化的方式也无法保证初始化的顺序
  2. 统一管理的方式可以明显提升 app 初始化速度,注:仅限于用较多 ContentProvider 来初始化应用的 app,反之不是不能用,只是没有优化效果


依赖

dependencies {
    implementation("androidx.startup:startup-runtime:1.0.0")
}
复制代码


使用 AppStartup 初始化全局单例对象(main 分支)

  1. Car 对象
class Car(private val name: String) {
    companion object {
        var instance: Car? = null
        fun getInstance(name: String): Car {
            if (instance == null) {
                instance = Car(name)
            }
            return instance!!
        }
    }
    override fun toString(): String {
        return "$name  ${Random.nextInt(100)}"
    }
}
复制代码


  1. 首先需要实现一个 Initializer
class AndroidInitializer : Initializer<Car> {
    override fun create(context: Context): Car {
        return Car.getInstance("出租车")
    }
    override fun dependencies(): MutableList<Class<out Initializer<*>>> {
        return mutableListOf()
    }
}
复制代码


  1. 在代码中注册 AndroidInitializer
<provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
          >
            <meta-data
                android:name="com.ananananzhuo.appstartupdemo.AndroidInitializer"
                android:value="androidx.startup" />
        </provider>
复制代码


  1. 分析

本例中 Car 对象,Car 对象内部维护了一个全局单例方法 getInstance。

前面说了,AppStartup 是用来维护全局单例的,那么实际上这个单例的初始化就是通过我们定义的 AndroidInitializer 对象 create 方法来初始化的。


  1. 我们会在 MainActivity 中调用 Car 的 toString 方法,代码如下
logEE(Car.getInstance("小汽车:").toString())
        logEE(Car.getInstance("小汽车:").toString())
        logEE(Car.getInstance("小汽车:").toString())
复制代码

我们调用了,三次 toString 方法

代码输出如下:

image.png

我们 MainActivity 中代码 getInstance 传入的参数是 "小汽车",但是打印的却是 "出租车"。查看 AndroidInitializer 中的代码发现,我们在 AndroidInitializer 中的 create 方法中创建对象的参数是 "出租车"。

由此可以证明,我们的全局 Car 单例在 AndroidInitializer 中就已经初始化完成了。


手动初始化组件

上一节中我们使用在 Manifest 中注册组件的方式实现 Car 对象的自动初始化。

但是,实际上我们是可以不在 Manifest 中注册的方式实现初始化的,手动初始化的方式如下:

AppInitializer.getInstance(this)
            .initializeComponent(AndroidInitializer::class.java)
复制代码

这种方式的弊端是一次只能初始化一个组件


实现相互依赖的多实例的初始化(分支:multimodule)

通过上一节的学习,你可能会有这样的疑问:AppStartup 啥用没有吧,我直接在 Application 中一行代码初始化不香吗,非要用你这种方式???

那么现在我就要用 AppStartup 实现多实例的初始化,让你进一步了解 AppStartup 的应用


我们这一节的逻辑先描述一下:

本例中我们需要创建两个对象,Person 和 Noodle,两者都是全局单例的。

Person 持有 Noodle 对象的引用,

Person 中有一个 eat 方法,本例中我们的 eat 会输出一行 "某某人" 吃 "面条" 的日志

废话不多说,上代码:

不要嫌代码长,都是一看就懂的逻辑

  1. Person 和 Noodle
class Person(val name:String) {
    private var noodle: Noodle? = null
    companion object {
        private var instance: Person? = null
        fun getInstance(name:String): Person {
            if (instance == null) {
                instance = Person(name)
            }
            return instance!!
        }
    }
    fun addNoodle(paramsnoodle: Noodle) {
        noodle = paramsnoodle
    }
    fun eat() {
        logEE("${name} 吃 ${noodle?.name}")
    }
}
复制代码


class Noodle {
    val name = "面条"
    companion object {
        private var instance: Noodle? = null
        fun getInstance(): Noodle {
            if (instance == null) {
                instance = Noodle()
            }
            return instance!!
        }
    }
}
复制代码


  1. PersonInitializer、NoodleInitializer
class PersonInitializer : Initializer<Person> {
    override fun create(context: Context): Person {
        return Person.getInstance("李白").apply {
            addNoodle(Noodle.getInstance())
        }
    }
    override fun dependencies(): MutableList<Class<out Initializer<*>>> {
        return mutableListOf(NoodleInitializer::class.java)
    }
}
复制代码


class NoodleInitializer:Initializer<Noodle> {
    override fun create(context: Context): Noodle {
        return Noodle.getInstance()
    }
    override fun dependencies(): MutableList<Class<out Initializer<*>>> {
        return mutableListOf()
    }
}
复制代码

这两个组件中 PersonInitializer 的 create 方法中创建了 Person 的实例,并向里面添加 Noodle 的实例。


划重点:

PersonInitializer 的 dependencies 方法中返回了 mutableListOf(NoodleInitializer::class.java)。这句代码的意思是在 PersonInitializer 中的 Person 初始化之前会先初始化 NoodleInitializer 中的 Noodle 实例,然后当 PersonInitializer 中 addNoodle 的时候 Noodle 全局单例已经创建好了。

  1. 调用吃面条方法
Person.getInstance("杜甫").eat()
复制代码
  1. 打印日志输出

image.png

日志输出符合我们的预期

多实例的注册组件方式如下,我们将 PersonInitializer、NoodleInitializer 都被注册到 meta-data 中了。

实际上,NoodleInitializer 的组件是完全可以不注册的,因为在 PersonInitializer 的 dependencies 中已经声明了 NoodleInitializer 组件。

<provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false">
            <meta-data
                android:name="com.ananananzhuo.appstartupdemo.PersonInitializer"
                android:value="androidx.startup" />
            <meta-data
                android:name="com.ananananzhuo.appstartupdemo.NoodleInitializer"
                android:value="androidx.startup" />
        </provider>
复制代码


使用 AppStartup 进行 sdk 开发(分支:sdk_develop)

本例介绍 sdk 开发中 AppStartup 的使用,实际上与应用开发是一样的,但是感觉还是有必要说一下。

在本例中我们新建了一个 library 的 module,在 library 里面编写了我们的 AppStartup 的代码逻辑,然后将 Library 打包成 arr,集成到 app 模块中,在 app 的 Manifest 中注册组件,并调用组件的相关方法。

  1. aar 集成

image.png

  1. library 中的代码
class LibraryInitializer:Initializer<Student> {
    override fun create(context: Context): Student {
        return Student.getInstance()
    }
    override fun dependencies(): MutableList<Class<out Initializer<*>>> {
       return mutableListOf()
    }
}
复制代码


class Student(val name: String) {
    companion object {
        private val student = Student("安安安安卓")
        fun getInstance(): Student {
            return student
        }
    }
    fun study() {
        Log.e("tag", "${name}  好好学习")
    }
}
复制代码


  1. Manifest 中注册组件
<provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="com.ananananzhuo.appstartupdemo.androidx-startup"
            android:exported="false"
          >
            <meta-data
                android:name="com.ananananzhuo.library.LibraryInitializer"
                android:value="androidx.startup" />
        </provider>
复制代码


  1. 日志打印

image.png


  1. 结论

通过这种方式,第三方 sdk 只需要定义自己的 AppStartup 组件就可以,我们在注册组件的时候在 manifest 中添加第三方组件的信息就可以完成第三方组件的初始化了。

这极大的避免了某些自以为是的 sdk,打着方便我们集成的名义搞 ContentProvider 初始化恶心我们

以后如果你合作的第三方 sdk 提供方再出现 ContentProvider 的初始化方式恶心你,那么拿出我的文章好好教他做人。



相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
18天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
58 3
|
3月前
|
缓存 小程序 索引
uni-app开发微信小程序时vant组件van-tabs的使用陷阱及解决方案
uni-app开发微信小程序时vant组件van-tabs的使用陷阱及解决方案
268 1
|
3月前
|
存储 API 数据库
uniapp APP自动更新组件
uniapp APP自动更新组件
111 1
|
3月前
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
55 6
|
3月前
|
存储 前端开发 UED
uni-app:基础组件 (下)
本文介绍了多种前端组件及其用法,包括:label 组件用于表单元素的标签;picker 组件用于实现日期、时间及普通列表的选择器;textarea 组件用于输入多行文本,并可通过 v-model 双向绑定数据;process 组件用于显示进度条;swiper 组件用于轮播图展示;match-media 组件根据屏幕尺寸展示内容;audio 组件用于播放音频;switch 组件用于开关选择;scroll-view 组件实现滚动视图功能;以及 storage 的使用方法,如设置、获取和移除本地存储等。
|
3月前
|
存储 前端开发 JavaScript
uni-app:基础组件 (上)
本文介绍了uni-app中多个组件的使用方法,包括存储操作、图标展示、按钮样式、表单输入、导航跳转和输入框控制等。通过具体代码示例展示了如何设置存储键值、使用不同类型的按钮、实现表单提交与重置功能、控制输入框的显示与清除等功能。
|
4月前
|
移动开发 小程序 前端开发
uni-app组件样式修改不生效
uni-app组件样式修改不生效
|
5月前
|
XML 数据格式
【Azure Logic App】在Logic App中使用 Transfer XML组件遇见错误 undefined
【Azure Logic App】在Logic App中使用 Transfer XML组件遇见错误 undefined
|
6月前
|
存储 前端开发
useEffect问题之在子组件的副作用中更新父组件的状态如何解决
useEffect问题之在子组件的副作用中更新父组件的状态如何解决
|
6月前
|
JSON JavaScript 小程序

热门文章

最新文章