如何在 Android/Kotlin App 上通过 Koin 注入在 BaseActivity 中初始化/注入通用 ViewModel

Posted

技术标签:

【中文标题】如何在 Android/Kotlin App 上通过 Koin 注入在 BaseActivity 中初始化/注入通用 ViewModel【英文标题】:How to initialize/inject generic ViewModel in BaseActivity by Koin injection on Android/Kotlin App 【发布时间】:2018-07-24 10:57:21 【问题描述】:

我正在使用 Kotlin 和 android 架构组件(ViewModel、LiveData)构建新的 Android 应用程序的架构,并且我还使用 Koin 作为我的依赖注入提供程序。

问题是我无法通过 koin 注入在 BaseActivity 中以通用方式初始化 ViewModel。当前代码如下所示:

abstract class BaseActivity<ViewModelType : ViewModel> : AppCompatActivity() 

    // This does not compile because of the generic type
    private val viewModel by lazy 
        // Koin implementation to inject ViewModel
        getViewModel<ViewModelType>()
    

    @CallSuper
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        Fabric.with(this, Crashlytics())
    

    /**
     * Method needed for Calligraphy library configuration
     */
    @CallSuper
    override fun attachBaseContext(newBase: Context) 
        super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase))
    

我想知道是否有办法在 Kotlin 中做到这一点,因为我很确定我可以轻松地在 Java 中做到这一点。 谢谢。

【问题讨论】:

【参考方案1】:

koin 团队在0.9.0-alpha-11 版本中提供了解决方案,最终代码如下所示:

open class BaseActivity<out ViewModelType : BaseViewModel>(clazz: KClass<ViewModelType>) :
    AppCompatActivity() 

    val viewModel: ViewModelType by viewModel(clazz)

    fun snackbar(message: String?) 
        message?.let  longSnackbar(find(android.R.id.content), it) 
    

    fun toast(message: String?) 
        message?.let  longToast(message) 
    

【讨论】:

val viewModel: ViewModelType by viewModelByClass(clazz)替换val viewModel: ViewModelType by viewModel(clazz) 有没有办法防止必须通过 Class 和 Generic?扩展时,您必须这样做: class Other:BaseActivity(VMClass::class) @MerthanErdem 在下面查看我的答案【参考方案2】:

这是不将Class and Generic 传递给基本实现的示例

在您的基础片段/活动中:

abstract class BaseFragment<T : BaseViewModel> : Fragment() 

  ...

  @Suppress("UNCHECKED_CAST")
  private val clazz: KClass<T> = ((this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>).kotlin

  protected val viewModel: T by viewModel(clazz = clazz)
  
  ...

它看起来很难看,但它确实有效。

【讨论】:

【参考方案3】:

您可以为您的 ViewModel 使用委托版本声明,并避免直接使用惰性表达式。试试这个:

abstract class BaseActivity<T : ViewModel> : AppCompatActivity() 

    val model by viewModel<T>()


这会让你变得懒惰

getViewModel<T>()

关注快速参考:https://insert-koin.io/docs/1.0/getting-started/android-viewmodel/

希望它会有所帮助。

【讨论】:

这个不行,还是要reified type parameter 这不起作用,因为它是具体的类型参数,你必须使用类本身

以上是关于如何在 Android/Kotlin App 上通过 Koin 注入在 BaseActivity 中初始化/注入通用 ViewModel的主要内容,如果未能解决你的问题,请参考以下文章

Android Kotlin:null 不能转换为非 null 类型 com.android.app.ui.category.CategoryAdapter.ViewHolder 想要在 recycl

android:kotlin语言使用greendao3,跨平台app开发框架

Android kotlin 组件间通讯 - LiveEventBus 及测试(更新中)

如何在 Android Kotlin 中创建 BottomSheet

如何在 Android (Kotlin) 中的 onSuccessListener 之外分配位置坐标?

Android kotlin获取当前通知是否打开