首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >StateFlow收集发射NullPointerException

StateFlow收集发射NullPointerException
EN

Stack Overflow用户
提问于 2020-12-31 12:37:53
回答 4查看 2.1K关注 0票数 1

我的存储库层有一个MutableStateFlow,在我的ViewModel中收集它。我在一些用户设备上得到了这个NPE

代码语言:javascript
复制
Fatal Exception: java.lang.NullPointerException
       at a.b.c.ui.viewmodel.HomeViewModel$collectFlowState$$inlined$collect$1.emit(HomeViewModel.java:189)
       at a.b.c.ui.viewmodel.HomeViewModel$collectFlowState$$inlined$collect$1$1.invokeSuspend(HomeViewModel.java:12)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(BaseContinuationImpl.java:33)
       at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTaskKt.java:176)
       at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTaskKt.java:111)
       at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.java:308)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.java:318)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.java:400)
       at kotlinx.coroutines.android.HandlerContext$scheduleResumeAfterDelay$$inlined$Runnable$1.run(HandlerContext.java:19)
       at android.os.Handler.handleCallback(Handler.java:883)
       at android.os.Handler.dispatchMessage(Handler.java:100)
       at android.os.Looper.loop(Looper.java:237)
       at android.app.ActivityThread.main(ActivityThread.java:7830)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1040)

MutableStateFlow是非空数据,如果数据为null,应用程序会更早崩溃。

我在存储库(生产者)层上使用StateFlow的一个例子:

代码语言:javascript
复制
data class ApiData(...)
private val INITIAL = ApiData(...)
private var someState = INITIAL

private val dataSF = MutableStateFlow(someState)

fun dataFlow() = dataSF

// called on remote api success, we poll for updated data (delta) from the server
fun onDataChangeAvailable(x: Int, y: Double) {
        someState = someState.copy(x = x, y= y)
        dataSF.value = someState
}

ViewModel (消费者)方面:

代码语言:javascript
复制
private val repository // constructor injected; repository is Application scoped
private val job = SupervisorJob()
private val uiScope = CoroutineScope(Dispatchers.Main + job)
// Viewmodel init block
init {
     uiScope.launch {
                repository.dataFlow().collect { // crash sometimes here.
                    // consume values
                }
        }
}

override fun onCleared() {
        job.cancel()
        super.onCleared()
    }

来自StateFlow文档

状态流永远不会完成。对状态流上的Flow.collect的调用永远不会正常完成,Flow.launchIn函数启动的协同线也不会正常完成。

流文档建议捕获这样的异常

代码语言:javascript
复制
try {
    flow.collect { value ->
        println("Received $value")
    }
} catch (e: Exception) {
    println("The flow has thrown an exception: $e")
}

那么,是否建议吞掉来自collectStateFlow的所有异常,还是只吞并由生产者端抛出的异常?NPE的一般原因是什么?

EN

回答 4

Stack Overflow用户

发布于 2021-08-09 08:51:11

“如果我们只打电话给cancel,那并不意味着协同工作就会停止。”

我解决了这个问题,用ensureActive()检查协同线是否处于活动状态。

代码语言:javascript
复制
...
       job = uiScope.launch {
                ensureActive()
                repository.dataFlow().collect { // crash sometimes here.
                    // consume values
                }
        }

override fun onCleared() {
        job.cancel()
        super.onCleared()
    }

您可以在如何取消收集到的StateFlow?中看到该溶质的详细信息。

票数 1
EN

Stack Overflow用户

发布于 2022-01-17 14:31:46

我也面临着同样的问题。实际上,我正在将StateFlow映射到其他东西并收集它。在映射过程中,我使用了!!符号!去掉那个符号解决了我的问题。

票数 1
EN

Stack Overflow用户

发布于 2020-12-31 13:42:09

我认为这能解决你的问题

代码语言:javascript
复制
private val dataSF = MutableStateFlow<Int?>(someState)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65521021

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档