在 Android 中使用 Hilt 后无法创建视图模型实例

Posted

技术标签:

【中文标题】在 Android 中使用 Hilt 后无法创建视图模型实例【英文标题】:Cannot create instance of viewmodel after using Hilt in Android 【发布时间】:2020-10-09 19:13:58 【问题描述】:

这是我的AllFilesListViewModel 课程。

class AllFilesListViewModel @ViewModelInject constructor(
    private val pdfItemRepository: PdfItemRepository):ViewModel() 


这里是PdfItemRepository 类。

@Singleton
class PdfItemRepository @Inject constructor(private val pdfItemDao: PdfItemDao)


对于pdfItemDao。我创建了一个名为 DatabaseModule 的模块。下面是代码 -

@Module
@InstallIn(ApplicationComponent::class)
object DatabaseModule 

    @Provides
    fun provideDatabase(@ApplicationContext context: Context):AppDatabase
        return AppDatabase.getDataBase(context)
    

    @Provides
    fun providePdfItemDao(database:AppDatabase):PdfItemDao
        return database.pdfItemDao()
    

这是我使用 viewModel 的片段类 AllFilesFragment.kt

@androidEntryPoint
class AllFilesFragment:Fragment()

    private lateinit var binding:AllFilesFragmentBinding
    private val viewModel by viewModels<AllFilesListViewModel>()


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        binding = AllFilesFragmentBinding.inflate(inflater,container,false)
        context?: return binding.root
        initThings()
        subscribeUi()
        return binding.root
    

这是logcat 文件。

06-19 19:22:20.203 23753-23753/com.emptysheet.pdfreader_autoscroll E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.emptysheet.pdfreader_autoscroll, PID: 23753
    java.lang.RuntimeException: Cannot create an instance of class com.emptysheet.pdfreader_autoscroll.homeScreen.viewModel.AllFilesListViewModel
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
        at androidx.hilt.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:69)
        at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:69)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
        at com.emptysheet.pdfreader_autoscroll.homeScreen.AllFilesFragment.getViewModel(AllFilesFragment.kt)
        at com.emptysheet.pdfreader_autoscroll.homeScreen.AllFilesFragment.subscribeUi(AllFilesFragment.kt:72)
        at com.emptysheet.pdfreader_autoscroll.homeScreen.AllFilesFragment.onCreateView(AllFilesFragment.kt:64)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:442)
        at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
        at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
        at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
        at androidx.viewpager2.adapter.FragmentStateAdapter.placeFragmentInViewHolder(FragmentStateAdapter.java:341)
        at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:276)
        at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:67)
        at androidx.recyclerview.widget.RecyclerView.dispatchChildAttached(RecyclerView.java:7556)
        at androidx.recyclerview.widget.RecyclerView$5.addView(RecyclerView.java:860)
        at androidx.recyclerview.widget.ChildHelper.addView(ChildHelper.java:107)
        at androidx.recyclerview.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:8601)
        at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8559)
        at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8547)
        at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1641)
        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
        at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
        at android.view.View.layout(View.java:15689)
        at android.view.ViewGroup.layout(ViewGroup.java:5048)
        at androidx.viewpager2.widget.ViewPager2.onLayout(ViewPager2.java:527)
        at android.view.View.layout(View.java:15689)
        at android.view.ViewGroup.layout(ViewGroup.java:5048)
        at com.google.android.material.appbar.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:148)
        at com.google.android.material.appbar.V

【问题讨论】:

【参考方案1】:

我在使用 Hilt 时会发生这种情况,问题的原因是我忘记在片段类的顶部添加 @AndroidEntryPoint 注释。 片段和宿主活动都应使用此注释进行注释。

【讨论】:

【参考方案2】:

在我在应用程序的 build.gradle 中使用 kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01' 后,这个问题得到了解决。我已经添加了kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"。我仍然不明白两个 BTW 之间的区别。如果有人知道。请给我解释一下。

【讨论】:

要支持@ViewModelInject,您还必须启用代码生成部门。请official docs了解更多详情 这解决了我的问题。想想我浪费了这么多时间,因为我没有仔细查看文档。 @Rajesh,我认为 theapache64 评论中的链接可能会提供一些解释。【参考方案3】:

这是由 AndroidX Lifecycle、AndroidX Core、AndroidX Activity 和 AndroidX Fragment 之间的版本不匹配造成的。

仅当getDefaultViewModelProviderFactory 可以被覆盖时,Hilt 才有效。

仅当该方法确实存在时才如此,如果您的依赖项已过时,则不会。即你的androidx.fragment低于1.2.0,你的androidx.activity低于1.1.0。

使用它,它会起作用的:

implementation "androidx.appcompat:appcompat:1.1.0"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "androidx.core:core-ktx:1.3.0"
implementation "androidx.activity:activity:1.1.0"

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0"

但目前,这就是它对我有用的原因:

implementation 'com.google.dagger:dagger:2.28'
kapt 'com.google.dagger:dagger-compiler:2.28'

// hilt
implementation 'com.google.dagger:hilt-android:2.28-alpha'
kapt 'com.google.dagger:hilt-android-compiler:2.28-alpha'
kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.28-alpha'
kaptTest 'com.google.dagger:hilt-android-compiler:2.28-alpha'
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'

随着

 apply plugin: 'dagger.hilt.android.plugin'

    classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
    

【讨论】:

我已经更新了依赖。但它仍然无法正常工作。 当我打开 Hilt 生成的文件时也是如此。有一个 getDefaultViewModelFactory 被覆盖。【参考方案4】:

@ViewModelInject 在较新的刀柄版本中已弃用

Reference

使用HiltViewModel

@HiltViewModel
class AllFilesListViewModel @Inject constructor(
    val pdfItemRepository: PdfItemRepository)
) : ViewModel() 


【讨论】:

【参考方案5】:

当我使用 Jetpack Compose、Hilt 和 Compose Navigation 时,我的方法是获取文档中的所有依赖项,并确保它们的所有版本都是最新的。关键是当你创建 ViewModel 时,你不应该使用= viewModel(),因为你已经使用了 Compose Navigation,而应该使用 = hiltViewModel()

【讨论】:

更多可以在这里找到:developer.android.com/jetpack/compose/libraries#hilt 在文档中,它使用 = viewModel.这是错误的!!它是更新!但是文档没有改变。懒惰的编辑器...... 君彦,谢谢!您对使用 hiltViewModel() 而不是 viewModel() 的评论确实解决了我的问题。过去几天我一直在为这个问题苦苦挣扎。奇怪的是 Android 文档有错误。【参考方案6】:

我之前遇到过这个问题,我已经通过将SavedStateHandle 传递给视图模型的主构造函数来解决它。

class AuthViewModel @ViewModelInject constructor(@Assisted private val savedState: SavedStateHandle) : ViewModel()

【讨论】:

【参考方案7】:

对于那些检查了上述所有解决方案但仍然无法正常工作的人,最后的检查是删除 Build 文件夹和 rebuild 项目,这将强制编译器在引擎盖下重新创建匕首 dependency graph .

就我而言,annotated 我的活动与@AndroidEntryPoint 仍然面临同样的问题。我已经删除了我的 build 文件夹和 rebuild 项目,它按预期工作。

【讨论】:

【参考方案8】:

在 alpha03 中,现在使用新的@HiltViewModel 和普通的@Inject,如下所示。

@HiltViewModel
class MyViewModel @Inject constructor(
    private val repository: Repository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel(), LifecycleObserver 

    // Some code

【讨论】:

【参考方案9】:

我今天也遇到了这个问题,我尝试了所有可能的修复建议,但无法消除错误。我只是在这里发布我的解决方案,以防将来有人遇到同样的问题。

就我而言,我有一个多模块项目,包含“UI 模块”、“ViewModel 模块”和“用例模块”。我这边的错误是我没有导入应用程序的 gradle 模块中的所有模块,我只是导入了 UI 模块。我在 Android 开发者网站上找到了这个关于 hilt 实现的注释:

注意:由于 Hilt 的代码生成需要访问所有使用 Hilt 的 Gradle 模块,因此编译您的 Application 类的 Gradle 模块还需要在其传递依赖项中包含您的所有 Hilt 模块和构造函数注入的类。

当我导入生成 DI 图所需的所有模块时,此崩溃消失了。

【讨论】:

以上是关于在 Android 中使用 Hilt 后无法创建视图模型实例的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 中通过 Hilt 进行依赖项注入

未解决的参考@HiltAndroidApp 或 Android 中的任何其他 Hilt 注释

社区说|Hilt 和 Kotlin Flow 在 Android 程序架构实现中的应用

Hilt 在 android 库中使用

在 Android 中通过 Hilt 进行依赖项注入

Android依赖注入框架Hilt基本使用