美文网首页Kotlin
Android使用Koin 一

Android使用Koin 一

作者: hao_developer | 来源:发表于2023-08-08 15:24 被阅读0次

    Koin是一个轻量级的依赖注入框架,它允许android应用程序轻松管理组件之间的依赖关系

    Koin的主要目标是使依赖注入变得简单,易于理解和使用。它采用纯Kotlin编写,无需代码生成或反射,而是基于函数DSL和注解,提供了一个简单而强大的方式来声明和管理依赖项

    添加依赖

    dependencies {
        def koin = "3.4.0"
        implementation("io.insert-koin:koin-core:$koin")
        implementation("io.insert-koin:koin-android:$koin")
        implementation("io.insert-koin:koin-android-compat:$koin")
    }
    
    • \color{red}{core}\为Koin的核心
    • \color{red}{android}\是Koin为Android提供的一些拓展方法
    • \color{red}{compat}\是Koin为Android组件提供的一些拓展方法
      除了上面三个以外,Koin还适配了compose、ktor,可谓是Android端和服务端都可以使用Koin来进行依赖注入,但是它和Hilt的不同是,Koin在kotlin的环境中使用。

    开始使用

    class KoinApp : Application() {
    
        override fun onCreate() {
            super.onCreate()
            startKoin {
                androidLogger()
                androidContext(this@KoinApp)
                modules(normalModule)
            }
        }
    }
    

    startkoin{}开启koin功能,然后进行一些配置

    • \color{red}{androidLogger()}\开启koin的运行日志
    • \color{red}{androidContext()}\绑定Application上下文,后面可以直接从koin中获取
    • \color{red}{module()}\传入koin的模块,次模块就是我们定义的依赖注入项

    使用Koin注入对象

    首先来使用Koin来注入一个常规的对象和单例对象,它不需要在对象的构造方法前面加入任何的注解,可以在原有的代码中无侵入式使用,这样就可以在之前的代码中进行Koin改造,下面来看看Koin是如何注入对象的

    // 定义两个对象,分别用来演示常规的对象和单例对象注入
    class KoinTest {
    
        fun test() {
            Log.d(TAG, "KoinTest test $this")
        }
    }
    
    class SingletonTest {
    
        fun test() {
            Log.d(TAG, "SingletonTest test $this")
        }
    }
    
    // normalMoudle就是来管理常规的对象注入
    val normalModule = module {
    
        factory { KoinTest() }
    }
    
    // singleModule则是用来单例对象注入
    val singleModule = module {
    
        single { SingletonTest() }
    }
    val moduleList = listOf(normalModule, singleModule)
    
    startKoin {
        androidLogger(Level.DEBUG)
        androidContext(this@KoinApp)
        // 将moduleList传入modules中,这样Koin就会帮助我们实现依赖注入
        modules(moduleList)
    }
    

    上面代码已经帮助我们实现了依赖注入,接着我们在使用注入对象的时候直接使用Koin的扩展方法by inject()就可以获取到对应的实例。

    class MainActivity : BaseActivity<ActivityMainBinding>() {
    
        // 使用Koin进行对象注入
        private val koinTest: KoinTest by inject()
        private val singletonTest: SingletonTest by inject()
    
        override fun initViewBinding(): ActivityMainBinding {
            return ActivityMainBinding.inflate(layoutInflater)
        }
    
        override fun onResume() {
            super.onResume()
            koinTest.test()
            singletonTest.test()
        }
    }
    
    # log
    KoinTest test com.example.koin.KoinTest@e0d5daf
    SingletonTest test com.example.koin.SingletonTest@29665bc
    

    注意看log中对象,\color{red}{KoinTest}\使用\color{red}{factory{}}\来进行注入的,应该是每次注入都会生成一个新的对象,而\color{red}{SingletonTest}\使用的是\color{red}{single{}}\来进行注入,每次注入对象都是不会变的,全局都是一个对象,下面我们看看在新的\color{red}{Activity}\中拿到的注入对象是否符合我们的预期。

    class SecActivity:BaseActivity<ActSecBinding>() {
    
        private val koinTest: KoinTest by inject()
        private val singletonTest: SingletonTest by inject()
    
        override fun initViewBinding(): ActSecBinding {
            return ActSecBinding.inflate(layoutInflater)
        }
    
        override fun onResume() {
            super.onResume()
            koinTest.test()
            singletonTest.test()
        }
    }
    
    # log
    KoinTest test com.example.koin.KoinTest@17dbb11
    SingletonTest test com.example.koin.SingletonTest@29665bc
    

    从log中可以看出,\color{red}{KoinTest}\确实是新的一个对象,而\color{red}{SingletonTest}\和之前注入的对象是同一个,这样我们就已经可以使用Koin来完成不同类型的对象注入了。

    Koin不仅可以使用\color{red}{by inject()}\来注入,也可以直接使用\color{red}{get()}\来注入一个对象,二者的区别在于一个是懒加载模式,一个是直接获取模式

    • \color{red}{inject()}\返回的是一个\color{red}{Lazy}\对象,内部依旧调用的是\color{red}{get()}\方法
    • \color{red}{get()}\返回的是需要注入的对象实例
      在平时使用中按需选择。

    和Hilt一对比,是否觉得使用Koin来实现依赖注入更方便了呢,在写法上面确实给人一种更加便捷的感觉,但是Koin和Hilt各有利弊吧,在后续的文章中会对这方面进行一个详细的介绍。

    Koin中使用ApplicationContext

    在开启Koin的时候,我们使用\color{red}{androidContext()}\传入了\color{red}{Application}\对象,这就为我们在后续需要使用\color{red}{Application}\的时候提供了无需传入参数的便捷,我们可以直接从Koin的\color{red}{get()}\获取到。

    class ContextTest(
        private val context: Application
    ) {
    
        fun test() {
            Log.d(TAG, "ContextTest test: ${context.getString(R.string.app_name)}")
        }
    }
    
    val normalModule = module {
        // 这里直接使用get()来注入context对象
        factory { ContextTest(get()) }
    }
    
    # log
    ContextTest test: koin
    

    Koin中使用ViewModel

    在Koin中注入一个\color{red}{ViewModel}\对象时,大致可以分为两种,一种是无参的\color{red}{ViewModel}\,不使用Koin的情况下,我们可以直接使用\color{red}{activity-ktx}\扩展库的\color{red}{by viewModels()}\来获取到\color{red}{ViewModel}\对象,这样确实要比Koin简单一些,但是对于第二种有参的\color{red}{ViewModel}\来说,Koin在写法上面要稍微具有优势一些,下面我们具体来看下两种的写法,从代码层面直观感受下Koin的魅力所在。
    #######注入无参ViewModel

    // 定义一个无参的ViewModel
    class KoinViewModel : ViewModel() {
    
        fun test() {
            Log.d(TAG, "KoinViewModel test")
        }
    }
    
    val viewModelModule = module {
        // 使用Koin的viewModel{}来注入KoinViewModel对象
        viewModel { KoinViewModel() }
    }
    
    // 在Activity中使用 by viewModel() 懒加载来获取KoinViewModel对象
    private val koinViewModel: KoinViewModel by viewModel()
    koinViewModel.test()
    
    # log
    KoinViewModel test
    

    对应\color{red}{ViewModel}\这种特殊的对象来说,Koin提供了\color{red}{viewModel{}}\方式帮助我们轻松的注入此对象,然后在使用的时候直接通过\color{red}{by viewModel()}\扩展方法来获取对应的\color{red}{ViewModel}\对象,它的内部实现也就是我们平时使用的\color{red}{ViewModelProvider}\来创建与之对应的\color{red}{ViewModel}\,Koin内部封装了一个\color{red}{KoinViewModelFactory}\,它是继承自\color{red}{ViewModelProvider.Factory}\

    注入有参ViewModel
    // 定义一个有参数的ViewModel
    class ParamsViewModel(
        private val repository: Repository
    ) : ViewModel() {
    
        fun test() {
            repository.test()
        }
    }
    
    class Repository() {
    
        fun test() {
            Log.d(TAG, "Repository test")
        }
    }
    
    val viewModelModule = module {
        single { Repository() }
        // 参数注解使用get()获取,无需手动传入
        viewModel { ParamsViewModel(get()) }
    }
    
    private val paramsViewModel: ParamsViewModel by viewModel()
    paramsViewModel.test()
    
    # log
    Repository test
    

    对于有参数的\color{red}{ViewModel}\来说,Koin只是要求我们多一步此参数的注入,其余和无参的使用过程几乎是一模一样,\color{red}{ParamViewModel}\需要我们传入一个\color{red}{Repository}\对象,那么我们就在\color{red}{moudle}\中将此对象通过\color{red}{single{}}\来先注入进去,告诉Koin它是一个单例对象,直接过去也行(也可以使用\color{red}{factor{}}\来进行注入),然后我们在注入\color{red}{ViewModel}\的时候通过Koin的\color{red}{get()}\方法获取即可。看到这是不是觉得Koin在此处深得人心,再也不用繁琐的通过\color{red}{ViewModelProvider.Factory}\来手动创建需要的参数了。

    相关文章

      网友评论

        本文标题:Android使用Koin 一

        本文链接:https://www.haomeiwen.com/subject/eewnpdtx.html