【问题标题】:CoroutineExceptionHandler doesn't work with ViewModelScope and KoinCoroutineExceptionHandler 不适用于 ViewModelScope 和 Koin
【发布时间】:2021-08-21 16:07:28
【问题描述】:

我有一种使用协程获取设备并使用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() }
}

【问题讨论】:

    标签: android exception kotlin-coroutines koin


    【解决方案1】:

    与Koin无关。

    日志显示viewModelScope.launch(exceptionHandler)中的exceptionHandler实际上为空,并抛出NullPointerException

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

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

    【讨论】:

    • 感谢您的回复。但是,如果我将fetchDevices 添加到onViewCreated,那么当我导航到另一个屏幕时,此方法将不断运行
    • 我该如何解决这个问题?
    • 您可以在 init 中运行它 - 只需将您的 exceptionHandler + 初始化移到 init 块之前。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-04
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    • 2013-04-22
    • 2016-08-03
    • 2012-01-27
    相关资源
    最近更新 更多