将ViewModel定义移动到包级别方法

时间:2017-06-13 12:08:27

标签: android kotlin

我想搬家:

ViewModelProviders.of(this).get(FooViewModel::class.java)

进入包级方法。像这样:

fun <T1, T2> T1.getViewModel(target: T1, targetViewModelClass: T2): Lazy<T2> {
    return ViewModelProviders.of(target).get(targetViewModelClass::class.java)
}

然而,这给了我2个错误:

enter image description here

enter image description here

问题:有没有办法完成此操作?

2 个答案:

答案 0 :(得分:4)

您的T1参数必须是FragmentFragmentActivity类型。目前没有。
另外,要调用::class.java,类型必须是不可为空的。目前是T2: Any?。此外,T2必须延长ViewModel 最后,对于简易API,您可以使用reified type

你可能想写:

inline fun <reified T: ViewModel> Fragment.getViewModel(): Lazy<T> {
  return lazy { ViewModelProviders.of(this).get(T::class.java) }
}

您现在可以将其用作:

class MyFragment : Fragment {

  fun foo() {
    val viewModelLazy = getViewModel<MyViewModel>()
  }
}

您可以对FragmentActivity执行相同操作。

答案 1 :(得分:1)

这应该可以解决问题:

fun <T1: Fragment, T2: Any> T1.getViewModel(targetViewModelClass: KClass<T2>): Lazy<T2> {
    return ViewModelProviders.of(this).get(targetViewModelClass.java)
}

用法:

class FragmentA : Fragment() {

    fun foo() {
        getViewModel(SomeViewModel::class)
    }

}

第一个问题是T1可能是您函数中的任何类型,但of方法只需要FragmentFragmentActivity。使用T1: FragmentT1限制为Fragment(当然,您也可以将其设为FragmentActivity。)

第二个问题似乎是targetViewModelClass可能为null,您可以通过将T2限制为Any的子类型来处理这个问题,null是所有类的基类Kotlin中不可空的类型。这样可以保证KClass不能作为该参数传入。

最后,根据@Kirill Rakhman的建议,我调整了第二个参数,以便可以使用{{1}}实例调用该函数。

以下是有关generic constraintsreified type parameters的官方文档。