天空 Blond - Code128
type: channel
link: https://skyblond.info/tag/Code128/
items: 【代码札记】从零开始的安卓应用开发 - P2

【代码札记】从零开始的安卓应用开发 - P2
type: item
date: 2023-04-28T17:07:00+08:00
description: 本文来介绍安卓APP的依赖注入，以及APP中一些机制的设计。依赖注入作为一个Java后端程序员，依赖注入这个概念肯定是不陌生：Spring框架这种理科男设计出来的玩意儿，真是要命。文档里没有几句人话，全是黑话和暗语，AOP，依赖注入，IOC，OOP，动态代理，CGLIB……只有他们能懂。正常人不可能看懂。想用旧代码加上个面向切面编程——看看，全是这种黑话，切面还编程。这是人话吗？弄了半天，一头大汗，也没弄明白。网上所谓的教程，是同一帮人写的，用同一套黑话。不弄了……credit: https://disksing.com/sao-gen-gen/43PS：在中国北方，切面是面条的一种。所以用面条编程，还是挺搞笑的如果读者不了解依赖注入的话，这里简单的举一个例子。按照面向对象的原则，我们在编程的时候希望把不同功能的代码放到不同的类里面。以汽车为例，Car需要有引擎，有电池，有车载电脑，有控制系统，而这些细节的实现不应该放在Car类里面，而是单独作为各自的类，通过接口来实现功能的调用。例如电池接口只需要供电和充电，而不必让调用者考虑这电池用的是什么材料，使用了什么技术。也许电池比较简单，那车的控制系统呢？一个控制系统会有好多输入输出，而这些输入输出也是不同的模块。这样一来，你要实例化一个汽车对象，就要先实例化它依赖的对象，而它依赖的对象又要依赖其他对象。日后如果你要对某个子系统新增一个依赖，那只能祝你好运了。而依赖注入就是来解决这个问题的。你只需要告诉依赖注入的框架如何制作这些基本的元素，而后依赖注入的框架就可以自动地根据需求来“装配”依赖，进而实例化对象。依赖注入经常和反转控制（IOC）一起说，因为在以前，是我们程序员来编写代码，控制不同组件实例化的时机，进而用实例化的结果来做事。引入了依赖注入之后，实例化组件的时机不再受我们的控制，反而是我们的代码将在不确定的时机被框架调用，这就是反转控制大体思想。当然，作为不使用依赖注入的反转控制，你也可以做一个全局共享的类，然后将所有需要的零部件放到这个类里面，通过静态成员按需使用。但这种情况下你还是需要维护一个类似于查找表的东西，我觉得这种手动的东西不如自动的框架来得优雅、简洁。对于安卓上的依赖注入框架，我喜欢叫他Dagger hilt，虽然dagger和hilt是两个分开的框架。关于这些库的历史渊源我就不讲了，谷歌上都可以查到。简单地说Dagger是一个谷歌维护的（官方已经钦定了）安卓上的依赖注入框架。它实现了JSR 330（Dependency Injection for Java），并且主要利用javax.inject.Inject注解来对非私有成员和构造器进行注入。Dagger是在编译时期确定依赖关系的，因此在编译时Dagger会根据你提供的对象和需要被构造的对象生成Factory类的代码，从而实现依赖注入。而Hilt则是一个使用了Dagger，并意在简化Dagger使用的库。在安卓上，一些特定的类是不能直接进行依赖注入的，例如安卓的Activity。要对这些类进行依赖注入，通常需要使用Dagger生成的工厂类。虽然Dagger帮我们生成了这些工厂类，但最终让安卓使用这些工厂类的代码还是要我们来写。而Hilt就是解决了这个问题，只需要一个注解，我们就可以直接享受到完整的依赖注入——不再需要额外的配置代码了。要开始依赖注入，我们首先需要提供一些可供注入的素材。这里为了简单考虑，所有的东西都作为单例模式注入。也就是说，这些对象一经创建，就要跟着整个APP的生命周期走。@Module @InstallIn(SingletonComponent::class) object AppModule { @Provides @Singleton fun provideAppDatabase(app: Application): AppDatabase = Room.databaseBuilder(app, AppDatabase::class.java, "vazan").build() @Provides @Singleton fun provideConfigDao(database: AppDatabase): ConfigDao = database.configDao }这里我们就提供了两个对象。一个是AppDatabase用来访问数据库的；另一个是从数据库里摘出来的DAO。至于最开始的那个Application从哪搞，这也好办：@HiltAndroidApp class VazanApplication : Application()直接创建一个就好了。当然，Provide并不是提供对象的唯一方式。Provide提供了一种教框架构造对象的方法。但有时候只是把参数传来传去，很没意思。…