【问题标题】:Kotlin does not understand ViewModelProviders.of(activity ?: fragment)Kotlin 不理解 ViewModelProviders.of(activity ?: fragment)
【发布时间】:2019-03-19 14:00:01
【问题描述】:

在我的Fragment 中,我使用ViewModelProviders 初始化ViewModel。 如果不是null,我希望它使用它的Activity,否则它自己(Fragment)。

private val viewModel: MainViewModel by lazy {
    ViewModelProviders.of(activity ?: this).get(MainViewModel::class.java)
}

以下函数都不能使用提供的参数调用。

  • of(Fragment) 在 androidx.lifecycle.ViewModelProviders 中定义
  • of(FragmentActivity) 在 androidx.lifecycle.ViewModelPro 中定义

似乎该语言不允许我调用冲突的方法签名(在of(Activity)of(Fragment) 之间。(这可能是可以理解的,也许编译器必须只引用一种方法并且不能在同一行链接到两者.) 是这样吗?

我现在必须使用

    activity?.let {
        ViewModelProviders.of(it).get(MainViewModel::class.java)
    } ?: run {
        ViewModelProviders.of(this).get(MainViewModel::class.java)
    }

有没有更好的方法?

【问题讨论】:

  • 是的,java 也不允许这样做,因为选择了方法重载at compile time,Kotlin 的字节码受到相同的限制,尽管它们可以在后台生成您的解决方法代码。只有当有一种方法可以采用ActivityFragment 的公共超类型时,它才会起作用,例如Context。如果你经常这样做,添加一个?稍微短一点:activity.let { it?.let { ViewModelProviders.of(it) } ?: ViewModelProviders.of(this) }.get(ViewModel::class.java)

标签: android kotlin android-viewmodel viewmodelproviders


【解决方案1】:

是的,这是编译器歧义,因为您同时传递了activitythis (fragment instance),它们在ViewModelProviders中有不同的实现。 p>

另一种方法是使用 when 条件,如下所示,(尽管您的方法也不错): p>

private val viewModel: MainViewModel by lazy {
    return@lazy when {
        activity != null -> {
            ViewModelProviders.of(activity as FragmentActivity).get(MainViewModel::class.java) // you can either pass activity object
        }
        else -> {
            ViewModelProviders.of(this).get(MainViewModel::class.java) // or pass fragment object, both are not possible at same time.
        }
    }
}

【讨论】:

    【解决方案2】:

    除了 Jeel 的回答,我建议如果你经常需要使用这种模式,你应该在 Fragment 上定义一个扩展函数以避免重复。例如:

    fun Fragment.getViewModelProvider() =
        activity?.let(ViewModelProviders::of) ?: ViewModelProviders.of(this)
    
    inline fun <reified T : ViewModel> Fragment.getViewModel() = 
        getViewModelProvider().get(T::class.java)
    

    从那里,您可以在任何Fragment 中拨打任一电话:

    val viewModel: MainViewModel = getViewModel()
    val viewModel = getViewModel<MainViewModel>()
    

    它将避免获取提供程序的样板文件以及具体指定 Java 类。

    【讨论】:

    • 我已经做了一个扩展,就像你写的第一个一样。但是感谢您发布此内容,因为我相信它会对其他人有所帮助。赞成。
    【解决方案3】:

    如果您使用的是 androidx,那么应该为生命周期添加两行:

     def lifecycle_version = "2.2.0-rc02"
        implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
        kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
    

    并像这样使用它:

     val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
    

    【讨论】:

    • 这是一个很好的答案。稍加改动就加这个(实现'androidx.lifecycle:lifecycle-extensions:2.2.0')
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 2019-05-26
    • 1970-01-01
    • 2017-10-23
    • 2018-04-14
    • 1970-01-01
    相关资源
    最近更新 更多