简体   繁体   English

为什么我的 kotlin 中的应用在调用协程时会崩溃?

[英]Why my app in kotlin crashes when calling a coroutine?

I am trying to call a function in a Fragment that is in my ViewModel but it crashes everytime its called and I don´t know why.我正在尝试在我的 ViewModel 中的片段中调用 function,但每次调用时它都会崩溃,我不知道为什么。 Here it´s the code:这是代码:

Call to a coroutine:调用协程:

binding.button.setOnClickListener {
            lifecycleScope.launch(Dispatchers.IO){
                courseViewModel.repository.insertCourse(getData())
            }
            Navigation.findNavController(it).popBackStack()
        }

The code of the function: suspend fun insertCourse(course: Course) = courseDAO.insertCourse(course) function的代码: suspend fun insertCourse(course: Course) = courseDAO.insertCourse(course)

If I don´t use the coroutine and just courseViewModel.repository.insertCourse(getData()) i get an error that says I have to call this function from other suspend function or a coroutine.如果我不使用协程而只使用courseViewModel.repository.insertCourse(getData())我会收到一条错误消息,提示我必须从其他挂起 function 或协程调用此 function。

This is the error:这是错误:

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$1$1.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$1$1.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) 

And my ViewModel is this:我的 ViewModel 是这样的:

class CourseViewModel(val repository: CourseRepository): ViewModel(){

In the fragment where I call the coroutine I declarate it like this: private val courseViewModel: CourseViewModel by activityViewModels()在我调用协程的片段中,我这样声明它: private val courseViewModel: CourseViewModel by activityViewModels()

First of all, you probably don't need to clutter up your fragment code with a coroutine in this situation.首先,在这种情况下,您可能不需要使用协程来扰乱您的片段代码。 Your ViewModel and/or Repository are better candidates, as they are responsible for the so-called business logic of your app.您的 ViewModel 和/或 Repository 是更好的候选者,因为它们负责您应用程序的所谓业务逻辑。 So ideally change your ViewModel function to use viewModelScope.launch(Dispatchers.IO) and then your fragment code can simply be:所以理想情况下将您的 ViewModel function 更改为使用viewModelScope.launch(Dispatchers.IO)然后您的片段代码可以简单地是:

binding.button.setOnClickListener {
    courseViewModel.insertCourse(getData())
    Navigation.findNavController(it).popBackStack()
}

Now regarding your ViewModel, you say you're declaring it as:现在关于您的 ViewModel,您说您将其声明为:

class CourseViewModel(val repository: CourseRepository): ViewModel()

However, the default ViewModelProvider (which is what is used by by activityViewModels() and by viewModels() to create your ViewModel) will only instantiate a zero argument ViewModel, which explains the error you are seeing.但是,默认的 ViewModelProvider( by activityViewModels()by viewModels()使用它来创建您的 ViewModel)只会实例化一个零参数ViewModel,这解释了您看到的错误。 (Side note: Google's current documentation of how all of this works is simply terrible; no nicer way to put it.) (旁注:谷歌目前关于所有这些工作原理的文档简直太糟糕了;没有更好的表达方式了。)

If you want to keep the repository as an argument, then you need to create a custom ViewModelFactory so that the ViewModelProvider knows how to instantiate it.如果你想保留存储库作为参数,那么你需要创建一个自定义的ViewModelFactory ,以便 ViewModelProvider 知道如何实例化它。 This Android Kotlin Fundamentals codelab has an example of how to create one.这个 Android Kotlin Fundamentals 代码实验室有一个如何创建一个的例子。

As an alternative to that, you can use dependency injection with Hilt and Jetpack, described here .作为替代方法,您可以将依赖项注入与 Hilt 和 Jetpack 结合使用,如此所述。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM