将ViewModel定义移动到包级别方法中
我想动议:
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) }
但是这给了我两个错误:
和
问题:有没有办法来完成这个?
您的T1
参数必须是Fragment
或FragmentActivity
类型。 目前没有。
另外,要调用::class.java
,类型必须是不可空的。 目前是T2: Any?
。 而且, T2
必须扩展ViewModel
。
最后,对于一个简单的API,你可以使用一个具体的类型 。
你可能想写:
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
。
这应该做的伎俩:
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
可能是你的函数中的任何类型,但是方法只需要一个Fragment
或一个FragmentActivity
。 使用T1: Fragment
将T1
限定为Fragment
(当然,您也可以创建这个FragmentActivity
)。
第二个问题似乎是targetViewModelClass
可能是null,你可以通过将T2
限制为Any
的子类型来处理这个问题,它是Kotlin中所有非空类型的基类。 这将保证null
不能作为参数传入。
最后,根据@Kirill Rakhman的建议,我调整了第二个参数,以便可以用KClass
实例调用该函数。
这里是关于通用约束和通用 类型参数的官方文档。