首页 > 解决方案 > CoroutineExceptionHandler 不适用于 ViewModelScope 和 Koin

问题描述

我有一种使用协程获取设备并用于viewModelScope.launch运行协程的方法。我想使用 捕获错误CoroutineExceptionHandler,但出现错误:

E/[Koin]: Instance creation error : could not create instance for [Factory:'com.test.presentation.viewModel.ActivateDeviceViewModel']: java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter context
        kotlin.coroutines.CombinedContext.plus(Unknown Source:2)
        kotlinx.coroutines.CoroutineContextKt.newCoroutineContext(CoroutineContext.kt:33)
        kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:52)
        kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
        kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
        kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
        com.test.presentation.viewModel.ActivateDeviceViewModel.fetchDevices(ActivateDeviceViewModel.kt:42)
        com.test.presentation.viewModel.ActivateDeviceViewModel.<init>(ActivateDeviceViewModel.kt:29)
        com.test.di.ModulesKt$viewModelModule$1$2.invoke(Modules.kt:63)
        com.test.di.ModulesKt$viewModelModule$1$2.invoke(Modules.kt:63)
        org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:51)
        org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
        org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:103)
        org.koin.core.scope.Scope.resolveInstance(Scope.kt:236)
        org.koin.core.scope.Scope.access$resolveInstance(Scope.kt:34)
        org.koin.core.scope.Scope$get$1.invoke(Scope.kt:199)
        org.koin.core.time.MeasureKt.measureDurationForResult(Measure.kt:75)
        org.koin.core.scope.Scope.get(Scope.kt:198)
        com.test.presentation.fragment.ActivateDeviceFragment$special$$inlined$inject$default$1.invoke(ComponentCallbackExt.kt:69)
        kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
        com.test.presentation.fragment.ActivateDeviceFragment.getViewModel(ActivateDeviceFragment.kt:39)
        com.test.presentation.fragment.ActivateDeviceFragment.access$getViewModel(ActivateDeviceFragment.kt:37)
        com.test.presentation.fragment.ActivateDeviceFragment$handleActivateDeviceResult$1$1.invokeSuspend(ActivateDeviceFragment.kt:51)
        kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        androidx.lifecycle.DispatchQueue.drainQueue(DispatchQueue.kt:75)
        androidx.lifecycle.DispatchQueue.resume(DispatchQueue.kt:54)
        androidx.lifecycle.LifecycleController$observer$1.onStateChanged(LifecycleController.kt:40)
        androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
        androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
        androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
        androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
        androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
        androidx.fragment.app.Fragment.performStart(Fragment.java:3024)
        androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:568)
        androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:277)
        androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1327)
        androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2757)
        androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2707)
        androidx.fragment.app.Fragment.performStart(Fragment.java:3028)
        androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:568)
        androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:277)
        androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1327)
        androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2757)
        androidx.fragm. 

请告诉我我做错了什么以及如何解决?谢谢

分段

class ActivateDeviceFragment : Fragment(R.layout.fragment_activate_device) {
    private val viewModel: ActivateDeviceViewModel by inject()
    // ....
} 

查看模型

class ActivateDeviceViewModel constructor(
    private val activateDeviceUseCase: ActivateDeviceUseCase,
) : ViewModel() {

    init {
        fetchDevices()
    }

    private val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
        Timber.tag("test").d(throwable)
    }

    private fun fetchDevices() {
        viewModelScope.launch(exceptionHandler) {
        }
    }
}

koin 模块

val useCaseModule = module { 
    single { ActivateDeviceUseCase() }
}

val viewModelModule = module {
    viewModel { ActivateDeviceViewModel(get() }
}

标签: androidexceptionkotlin-coroutineskoin

解决方案


它与 Koin 无关。

日志显示exceptionHandlerinviewModelScope.launch(exceptionHandler)实际上为 null,并且抛出NullPointerException.

这是因为您触发了fetchDevices()内部init{},其中的实例化exceptionHandler尚未准备好(意味着它为空)。

因此,您不应该调用fetchDevices()inside init{}。例如,您可以onViewCreated(){ viewModel.fetchDevices }改为在 Fragment 中调用它。没事的。


推荐阅读