为什么我在 kotlin 中的应用程序在调用协程时会崩溃?
Why my app in kotlin crashes when calling a coroutine?
我试图在我的 ViewModel 中的 Fragment 中调用一个函数,但每次调用时它都会崩溃,我不知道为什么。
这是代码:
调用协程:
binding.button.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO){
courseViewModel.repository.insertCourse(getData())
}
Navigation.findNavController(it).popBackStack()
}
函数代码:
suspend fun insertCourse(course: Course) = courseDAO.insertCourse(course)
如果我不使用协程而只是 courseViewModel.repository.insertCourse(getData())
我会收到一条错误消息,提示我必须从其他挂起函数或协程调用此函数。
这是错误:
2022-03-20 13:33:43.893 28396-28437/com.example.cursosmvvm E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.example.cursosmvvm, PID: 28396
java.lang.RuntimeException: Cannot create an instance of class domain.CourseViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:188)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:169)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
at ui.NewCourseFragment.getCourseViewModel(NewCourseFragment.kt:23)
at ui.NewCourseFragment.access$getCourseViewModel(NewCourseFragment.kt:20)
at ui.NewCourseFragment$onViewCreated.invokeSuspend(NewCourseFragment.kt:58)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Caused by: java.lang.InstantiationException: java.lang.Class<domain.CourseViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:186)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:169)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
at ui.NewCourseFragment.getCourseViewModel(NewCourseFragment.kt:23)
at ui.NewCourseFragment.access$getCourseViewModel(NewCourseFragment.kt:20)
at ui.NewCourseFragment$onViewCreated.invokeSuspend(NewCourseFragment.kt:58)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
我的 ViewModel 是这样的:
class CourseViewModel(val repository: CourseRepository): ViewModel(){
在我调用协程的片段中,我这样声明它:private val courseViewModel: CourseViewModel by activityViewModels()
首先,在这种情况下,您可能不需要用协程来弄乱您的片段代码。您的 ViewModel and/or 存储库是更好的候选者,因为它们负责您应用程序的 so-called 业务逻辑。所以理想情况下将您的 ViewModel 函数更改为使用 viewModelScope.launch(Dispatchers.IO)
然后您的片段代码可以简单地是:
binding.button.setOnClickListener {
courseViewModel.insertCourse(getData())
Navigation.findNavController(it).popBackStack()
}
现在关于您的 ViewModel,您说您将其声明为:
class CourseViewModel(val repository: CourseRepository): ViewModel()
但是,默认的 ViewModelProvider(by activityViewModels()
和 by viewModels()
使用它来创建您的 ViewModel)只会实例化一个 零参数 ViewModel ,这解释了您看到的错误。 (旁注:Google 当前关于所有这些工作原理的文档简直太糟糕了;没有更好的表达方式了。)
如果您想将存储库作为参数保留,则需要创建一个自定义 ViewModelFactory so that the ViewModelProvider knows how to instantiate it. This Android Kotlin Fundamentals codelab 有一个如何创建的示例。
作为替代方法,您可以将依赖项注入与 Hilt 和 Jetpack 结合使用,如 here 所述。
我试图在我的 ViewModel 中的 Fragment 中调用一个函数,但每次调用时它都会崩溃,我不知道为什么。 这是代码:
调用协程:
binding.button.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO){
courseViewModel.repository.insertCourse(getData())
}
Navigation.findNavController(it).popBackStack()
}
函数代码:
suspend fun insertCourse(course: Course) = courseDAO.insertCourse(course)
如果我不使用协程而只是 courseViewModel.repository.insertCourse(getData())
我会收到一条错误消息,提示我必须从其他挂起函数或协程调用此函数。
这是错误:
2022-03-20 13:33:43.893 28396-28437/com.example.cursosmvvm E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.example.cursosmvvm, PID: 28396
java.lang.RuntimeException: Cannot create an instance of class domain.CourseViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:188)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:169)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
at ui.NewCourseFragment.getCourseViewModel(NewCourseFragment.kt:23)
at ui.NewCourseFragment.access$getCourseViewModel(NewCourseFragment.kt:20)
at ui.NewCourseFragment$onViewCreated.invokeSuspend(NewCourseFragment.kt:58)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Caused by: java.lang.InstantiationException: java.lang.Class<domain.CourseViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:186)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:169)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
at ui.NewCourseFragment.getCourseViewModel(NewCourseFragment.kt:23)
at ui.NewCourseFragment.access$getCourseViewModel(NewCourseFragment.kt:20)
at ui.NewCourseFragment$onViewCreated.invokeSuspend(NewCourseFragment.kt:58)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
我的 ViewModel 是这样的:
class CourseViewModel(val repository: CourseRepository): ViewModel(){
在我调用协程的片段中,我这样声明它:private val courseViewModel: CourseViewModel by activityViewModels()
首先,在这种情况下,您可能不需要用协程来弄乱您的片段代码。您的 ViewModel and/or 存储库是更好的候选者,因为它们负责您应用程序的 so-called 业务逻辑。所以理想情况下将您的 ViewModel 函数更改为使用 viewModelScope.launch(Dispatchers.IO)
然后您的片段代码可以简单地是:
binding.button.setOnClickListener {
courseViewModel.insertCourse(getData())
Navigation.findNavController(it).popBackStack()
}
现在关于您的 ViewModel,您说您将其声明为:
class CourseViewModel(val repository: CourseRepository): ViewModel()
但是,默认的 ViewModelProvider(by activityViewModels()
和 by viewModels()
使用它来创建您的 ViewModel)只会实例化一个 零参数 ViewModel ,这解释了您看到的错误。 (旁注:Google 当前关于所有这些工作原理的文档简直太糟糕了;没有更好的表达方式了。)
如果您想将存储库作为参数保留,则需要创建一个自定义 ViewModelFactory so that the ViewModelProvider knows how to instantiate it. This Android Kotlin Fundamentals codelab 有一个如何创建的示例。
作为替代方法,您可以将依赖项注入与 Hilt 和 Jetpack 结合使用,如 here 所述。