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

Android 将ViewModel定义移动到包级别方法中,android,kotlin,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)

我谨动议:

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)
}
funt1.getViewModel(目标:T1,目标视图模型类:T2):惰性{
返回ViewModelProviders.of(target.get)(targetViewModelClass::class.java)
}
但是,这给了我两个错误:



问题:有什么方法可以完成这项任务吗?

这应该可以做到:

fun <T1: Fragment, T2: Any> T1.getViewModel(targetViewModelClass: KClass<T2>): Lazy<T2> {
    return ViewModelProviders.of(this).get(targetViewModelClass.java)
}
第一个问题是
T1
可以是函数中的任何类型,但是
方法只接受
片段
片段活动
。使用
T1:Fragment
T1
限制为
片段
(当然,您也可以将此
片段活动

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

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


以下是关于和的官方文档。

这应该可以做到:

fun <T1: Fragment, T2: Any> T1.getViewModel(targetViewModelClass: KClass<T2>): Lazy<T2> {
    return ViewModelProviders.of(this).get(targetViewModelClass.java)
}
第一个问题是
T1
可以是函数中的任何类型,但是
方法只接受
片段
片段活动
。使用
T1:Fragment
T1
限制为
片段
(当然,您也可以将此
片段活动

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

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


这是关于和的正式文档。

您的
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) }
}
inline fun Fragment.getViewModel():Lazy{
返回lazy{ViewModelProviders.of(this.get)(T::class.java)}
}
您现在可以将其用作:

class MyFragment : Fragment {

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

您可以对
FragmentActivity
执行相同的操作
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) }
}
inline fun Fragment.getViewModel():Lazy{
返回lazy{ViewModelProviders.of(this.get)(T::class.java)}
}
您现在可以将其用作:

class MyFragment : Fragment {

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

您可以对
片段活动执行相同的操作

T
需要扩展
ViewModel
。我喜欢这个解决方案。要更改的一件事是
returnviewmodelproviders.of(this).get(T::class.java)
应该放在
lazy{…}
@Oleg Great!也许你可以用你的意思来编辑答案。我的意思是,如果一个方法返回
Lazy
,返回语句必须是
returnlazy{foo}
T
需要扩展
ViewModel
。我喜欢这个解决方案。要更改的一件事是
returnviewmodelproviders.of(this).get(T::class.java)
应该放在
lazy{…}
@Oleg Great!也许你可以用你的意思来编辑答案。我的意思是,如果一个方法返回
Lazy
,返回语句必须是
returnlazy{foo}
。我认为OP试图做的是将
实例作为第二个参数传递。想一想,传递
ViewModel
的实例有什么意义?如果你想检索
ViewModel
?我的答案已经确定,我试图保持原始代码的精神@nhaarman在另一个答案中有一个更为惯用的解决方案:)我认为OP试图做的是将
实例作为第二个参数传递。想一想,传递
ViewModel
的实例有什么意义?如果你想检索
ViewModel
?我的答案已经确定,我试图保持原始代码的精神@不过,尼亚曼在另一个答案中有更为惯用的解决方案:)