如何使用fragment-ktx中的viewModels来获取viewModel?

145

我正在使用单个viewModel来处理活动和所有片段的数据。

因此,为了初始化viewmodel,必须在所有片段的onActivityCreated中编写此设置代码。

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(activity!!).get(NoteViewModel::class.java)
    }

我正在查看Android KTX扩展页面 (点击这里)

发现我可以像这样初始化ViewModel:

    // Get a reference to the ViewModel scoped to this Fragment
    val viewModel by viewModels<MyViewModel>()

    // Get a reference to the ViewModel scoped to its Activity
    val viewModel by activityViewModels<MyViewModel>()
所以我在我的gradle(app)中添加了以下依赖项:
    //ktx android
    implementation 'androidx.core:core-ktx:1.0.2'
    implementation 'androidx.fragment:fragment-ktx:1.0.0'
    implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"

但是当我尝试在我的应用程序中使用viewModels/activityViewModels时,它们的引用未找到。

我想知道如何使用这些扩展,并带有一些基本示例。我尝试搜索示例,但没有找到。


你的ViewModel需要传入参数吗,比如repository或db? - IgorGanapolsky
@IgorGanapolsky 是的,它可以。我正在使用单个 VM,在所有片段之间共享。 - Anmol
你需要一个 ViewModelFactory - IgorGanapolsky
14个回答

116

最终我们得到了稳定版本。

使用implementation 'androidx.fragment:fragment-ktx:1.1.0'后,我遇到了另一个问题。

编译器错误:

无法将使用JVM目标1.8构建的字节码内联到正在使用JVM目标1.6构建的字节码中

build.gradle(模块::app

compileOptions {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}

kotlinOptions {
    jvmTarget = "1.8"
}

参考链接

经过以上所有步骤,问题已得到解决。


我正在开发一个多模块应用程序,有没有比在每个模块中都声明这个compileOption更好的方法? - Vikas Pandey
@VikasPandey compileOption 可以在全局项目 build.gradle 中使用。 - Paul Stelian

68
尝试
implementation 'androidx.fragment:fragment-ktx:1.1.0-beta02'

2021更新

此版本不再处于测试阶段,它与撰写本文时的最新稳定版本兼容。您还需要在碎片的Kotlin文件中导入它。

implementation 'androidx.fragment:fragment-ktx:1.3.2'
import androidx.fragment.app.activityViewModels

31
这个代理只能从Fragment中调用。但是,如果你添加了"androidx.activity:activity-ktx:1.0.0"依赖项的实现,你可以为Activity使用类似的代理。 - Denys Makhov
2
@Anmol,答案中的版本最近已经升级到稳定版。您需要至少使用1.1.0版本才能使用“by ViewModels()”。 - MowDownJoe
4
@DenysMakhov 错了。 fragment-ktx 同时适用于活动和片段。 - Dr.jacky
1
@Dr.jacky 是的,也许在一年之间有些变化了。 - Denys Makhov
10
在 Activity 中,使用 by viewModels() 就足够了,因为你已经在 Activity 中了。如果在 Fragment 中需要访问 Activity 的 ViewModel,则应该使用 by activityViewModels()。注意不要改变原来的意思。 - Sai
显示剩余7条评论

33

如果您想要使用Kotlin委托来管理ViewModel,则需要在项目中添加此依赖项。

//ViewModels delegation extentensions for activity
implementation 'androidx.activity:activity-ktx:1.3.1'

1
谢谢!这对我来说是解决方案。 - Cata
2
是的,这是正确的答案。谢谢。 - Nicolas Mage

16

虽然这理论上可以回答问题,但最好在此处包含答案的关键部分并提供链接作为参考。即请编辑您的答案以说明为什么截至2022年4月这是首选。 - Adriaan
@Adriaan提出了正确的建议。最好是主要示例引用,而不仅是分享解决方案的网页链接。 - A S M Sayem

3

注意:这也适用于Jetpack Compose

此处复制依赖项

当前的依赖关系于 2021年6月5日 如下:

dependencies {
    val activity_version = "1.2.3"

    // Java language implementation
    implementation("androidx.activity:activity:$activity_version")
    // Kotlin
    implementation("androidx.activity:activity-ktx:$activity_version")
}

3

针对谷歌员工:您的 Activity 应该继承 AppCompatActivity,而不是 Activity。


谢谢您注意到了这个问题! - Dmitriy Pavlukhin
1
另外,请确保使用小写字母v调用viewModels(),而不是ViewModels() - M.Ed

3

如果你遇到“找不到setter”的错误,请确保在ViewModel属性中使用val而不是var


3
您使用最新的 alpha 版本:
dependencies {
    implementation 'androidx.fragment:fragment-ktx:1.2.0-alpha01'
}

2
扩展函数viewModels(...)是在版本1.1.0-alpha03中添加的。因此,为了在您的应用程序中使用它,您需要实现与1.1.0-alpah03或更高版本匹配的fragment-ktx。
我刚刚发现了这一点,所以我选择使用版本1.1.0-rc01,因为我不想使用alpha/beta版本。

无法与1.2.0-alpha02一起使用。 - IgorGanapolsky

2
你可以实现
implementation 'androidx.fragment:fragment-ktx:1.1.0'

事实上,KTX包中的BY viewModels实现看起来像这样,你也可以自己实现一个扩展函数。
@MainThread
inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
        noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
        val application = application ?: throw IllegalArgumentException(
                "ViewModel can be accessed only when Activity is attached"
        )
        ViewModelProvider.AndroidViewModelFactory.getInstance(application)
    }

    return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接