Android App封装 —— DI框架 Hilt?Koin?

2,181 阅读3分钟

项目搭建经历记录

  1. Android App封装 ——架构(MVI + kotlin + Flow)
  2. Android App封装 —— ViewBinding
  3. Android App封装 —— DI框架 Hilt?Koin?
  4. Android App封装 —— 实现自己的EventBus

背景

前面的项目Github wanandroid例子我们可以看到,我们创建Repository和ViewModel的时候,都是直接创建的

class MainViewModel : BaseViewModel<MainState, MainIntent>() {
    private val mWanRepo = HomeRepository()
    ...
}


class MainActivity : BaseActivity<ActivityMainBinding>() {

    override fun onCreate(savedInstanceState: Bundle?) {
         mViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
     }
}

但是一般一个repository会被多个viewModel使用,我们不想创建多个同样类型的repository实例,这时候我们需要将WanRepository设置为单例。但是当代码越来越多,对象的共享依赖关系以及生命周期越来越复杂的时候,我们全部自己手写显然是比较复杂的。

所以Goolge强推我们使用DI(Dependency Injection)依赖注入来管理对象的创建,之前推出了强大的Dagger,但是由于难学难用,很少有人用到这个框架。后面又推出了Hilt,基于Dagger实现,针对于Android平台简化了使用方式,原理和Dagger是一致的。

本来准备将Hilt引用到项目中,后来发现了一个轻量级的DI框架koin,两者学习对比了一下之后还是决定使用Koin这个轻量级的框架,koin和Hilt的详细对比就不在此展开了,网上有很多文章。

那么就开始动工,准备在项目中集成koin吧。

koin

koin官网,官网永远是学习一个东西的最佳途径

1. 依赖

网上看到很多koin的使用案例,我看依赖的都是2.X的包

implementation "org.koin:koin-android:$koin_version"
implementation "org.koin:koin-android-viewmodel:$koin_version"

后面我去官网看了下文档,发现koin已经升级到3.x了,合并所有 Scope/Fragment/ViewModel API,只需要引用一个包就可以了

    implementation "io.insert-koin:koin-android:$koin_version" //3.3.1

2. 启动

添加好依赖后,可以在Application中启动koin,初始化koin的配置,代码如下

class App : Application() {
    override fun onCreate() {
        super.onCreate()

        startKoin {
            //开始启动koin
            androidLogger()
            androidContext(this@App)//这边传Application对象,这样你注入的类中,需要app对象的时候,可以直接使用
            modules(appModule)//这里面传各种被注入的模块对象,支持多模块注入
        }
    }
}

3. 模块Module

上文中的modules(appModule),是用来配置koin使用的Module有哪些,那么Module是什么呢?

Koin是以Module的形式组织依赖项,我们可以将可能用到的依赖项定义在Module中,也就是对象的提供者

val repoModule = module {
    single { HomeRepository() }
}

val viewModelModule = module {
    viewModel { MainViewModel(get()) }
}

val appModule = listOf(viewModelModule, repoModule)

上面这段代码就是定义了两个Module,一个我专门用来定义repository,一个专门用来定义viewModel。

然后通过get()inject(),表示在需要注入依赖项,也就是对象的使用者,这时就会在Module里面检索对应的类型,然后自动注入。

所以之前Repository的创建变为

val mWanRepo: HomeRepository by inject(HomeRepository::class.java)

并且依据single定义为了单例

进一步简化可以将repository写到ViewModel的构造方法中

class MainViewModel(private val homeRepo: HomeRepository) : BaseViewModel<MainState, MainIntent>() {
    ...
}

根据viewModel { MainViewModel(get()) }的定义,在构造MainViewModel的时候会自动因为get()填充HomeRepository对象

4. Activity中使用ViewModel

class MainActivity : BaseActivity<ActivityMainBinding>() {

    private val mViewModel by viewModel<MainViewModel>()
    
}

总结

koin和Hilt,大家可以看自己的习惯使用,Hilt的特点主要是利用注解生成代码,使用方便,效率也挺高的。koin我主要是看中它比较轻量级,可以快速入门使用。

项目地址:Github wanandroid