如何通过 Android/Kotlin App 上的 Koin 注入在 BaseActivity 中 initialize/inject 通用 ViewModel

How to initialize/inject generic ViewModel in BaseActivity by Koin injection on Android/Kotlin App

我正在使用 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 中轻松做到。 谢谢

您可以为您的 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/

希望对您有所帮助。

解决方案由 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) }
    }
}

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

在你的基地fragment/activity:

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)
  
  ...
}

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