HiltViewModel:无法创建类的实例

11

我正在使用Hilt。更新到1.0.0-alpha03后,我收到警告说@ViewModelInject已过时,应该使用@HiltViewModel。但是当我更改时,我遇到了错误:

java.lang.RuntimeException: Cannot create an instance of class com.example.LoginViewModel
...
Caused by: java.lang.NoSuchMethodException: com.example.LoginViewModel.<init> [class android.app.Application]

我之前的ViewModel长这样:

class LoginViewModel @ViewModelInject constructor(
    application: Application,
    private val repository: RealtimeDatabaseRepository
) : AndroidViewModel(application)
现在它看起来是这样的:
@HiltViewModel
class LoginViewModel @Inject constructor(
    application: Application,
    private val repository: RealtimeDatabaseRepository
) : AndroidViewModel(application)

ViewModel被注入的Fragment:

@AndroidEntryPoint
class LoginFragment : Fragment(R.layout.fragment_login)
{
    private val viewModel: LoginViewModel by activityViewModels()
}

注入的类:

@Singleton
class RealtimeDatabaseRepository @Inject constructor() { }

当我从ViewModel的构造函数中删除private val repository: RealtimeDatabaseRepository时,它可以正常工作。


我正在使用Hilt版本2.30.1-alpha,当我更新到2.31.2-alpha时,就像USMAN osman建议的那样,错误消失了。


2
你的Activity也有@AndroidEntryPoint吗?此外,对于已经使用了@Inject构造函数注释的类,你不需要一个@Provides方法。 - IR42
是的,Activity有@AndroidEntryPoint。但如果我想让我的存储库成为单例,我不必使用@Provides吗?我可以用@Singleton注释一个类,这就足够了吗? - iknow
是的,您可以使用作用域注释来注释类 @Singleton class RealtimeDatabaseRepository @Inject constructor() { } - IR42
好的,谢谢。我已经删除了提供函数,但错误仍然相同。 - iknow
3个回答

13

在新版本的Hilt中,许多内容都已更改。
您还需要将您的Hilt Android、Hilt编译器和Hilt Gradle插件升级到:2.31-alpha
我按照您的方式创建了一个模拟示例,遇到了相同的问题,在查看了Hilt文档后,找到了一种新的方法来向ViewModel注入依赖项,您需要为将要注入到viewModel的依赖项制作单独的模块,并使用名为ViewModelComponent的特殊组件进行注入:

@Module
@InstallIn(ViewModelComponent::class) // this is new
object RepositoryModule{

    @Provides
    @ViewModelScoped // this is new
    fun providesRepo(): ReposiotryIMPL { // this is just fake repository
        return ReposiotryIMPL()
    }

}

以下是有关 ViewModelComponentViewModelScoped 的文档内容:

所有 Hilt 视图模型都由 ViewModelComponent 提供,其生命周期与 ViewModel 相同,即它可以在配置更改后保留。要将依赖项作用域限定为视图模型,请使用 @ViewModelScoped 注释。

@ViewModelScoped 类型将使得给定作用域类型的单个实例提供于注入到 Hilt 视图模型中的所有依赖项之间。
链接:https://dagger.dev/hilt/view-model.html

然后您的 viewModel:

@HiltViewModel
class RepoViewModel @Inject constructor(
    application: Application,
    private val reposiotryIMPL: ReposiotryIMPL
) : AndroidViewModel(application) {}

更新
与我在上面的示例中使用ViewModelComponentViewModelScoped不同,您并非必须使用这些。您也可以根据您的用例使用其他作用域组件
此外,请阅读文档,我在上面放置了Dagger-Hilt的链接。


1
谢谢,现在它可以工作了。我所需要做的就是将依赖项更新到 2.31-alpha - iknow
2
天啊,我忘记更新 kapt 了,结果花了五个小时才找到为什么这不起作用的解决方案...读了五遍答案后,我终于弄明白了,如果你的应用程序崩溃,请三重检查版本。 - Marian Pavel
1
如果您想要超出ViewModel的生命周期,那么使用@Singleton范围也是可以的: @InstallIn(SingletonComponent::class) - Henk-Martijn
我可以确认,更新依赖项有时是消除错误的唯一遗漏。hilt-androidhilt-android-compiler 需要具有相同的版本。 - Tom Ladek

10
我看到这种情况发生在使用ViewModel的Fragment/Activity缺少@AndroidEntryPoint注释的情况下,例如:
import androidx.fragment.app.viewModels

@AndroidEntryPoint
class SampleFragment: BaseFragment() {
     val viewModel: SampleFragmentViewModel by viewModels()
}

如果缺少注释,将会发生与您描述的完全相同的错误。

1

我的错误很愚蠢,但可能会帮助未来的人。我向一个特性模块添加了 ViewModel,但忘记在特性的 build.gradle 文件中添加 kapthilt 依赖项,这意味着 Hilt 永远看不到 ViewModel。


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