【问题标题】:How to initialize/inject generic ViewModel in BaseActivity by Koin injection on Android/Kotlin App如何在 Android/Kotlin App 上通过 Koin 注入在 BaseActivity 中初始化/注入通用 ViewModel
【发布时间】: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 中做到这一点。 谢谢。

【问题讨论】:

    标签: android mvvm dependency-injection kotlin viewmodel


    【解决方案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
      • 这不起作用,因为它是具体的类型参数,你必须使用类本身
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-07
      • 2022-01-08
      相关资源
      最近更新 更多