在 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 后无法创建视图模型实例的主要内容,如果未能解决你的问题,请参考以下文章
未解决的参考@HiltAndroidApp 或 Android 中的任何其他 Hilt 注释