You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

简单Observer出现UndeliverableException,求助定位与解决

解决Observer遇到的UndeliverableException问题

这个异常的核心原因是:Flow/LiveData的观察者已被取消/销毁,但上游仍在发送异常,且没有指定的异常接收处理逻辑。以下是针对你提到的几个类的具体解决步骤:

1. 在NotificationLiveData中拦截上游异常

如果是自定义LiveData,要在数据更新的源头捕获异常,避免异常直接传递给已销毁的观察者:

class NotificationLiveData : LiveData<NotificationData>() {
    fun updateFromLocationService() {
        try {
            // 调用LocationService获取数据的逻辑
            val locationData = LocationService.getCurrentLocation()
            postValue(NotificationData.Success(locationData))
        } catch (e: Exception) {
            // 将异常包装为错误状态发送,而非直接抛出
            postValue(NotificationData.Error(e.message ?: "未知错误"))
        }
    }
}

如果LiveData基于Flow转换,要在Flow转换时添加catch操作符:

val notificationLiveData = locationService.locationFlow
    .catch { e -> emit(NotificationData.Error(e)) }
    .asLiveData()

2. 在Observer订阅时处理内部异常

确保Observer的onChanged方法中没有未捕获的异常,同时依托生命周期自动管理订阅:

// 在Activity/Fragment中
notificationLiveData.observe(this) { data ->
    try {
        when(data) {
            is NotificationData.Success -> NotificationManager.showNotification(data.data)
            is NotificationData.Error -> Log.e("Notification", "数据错误: ${data.msg}")
        }
    } catch (e: Exception) {
        // 捕获Observer内部处理逻辑的异常,避免扩散
        Log.e("ObserverError", "处理通知数据失败", e)
    }
}

如果使用Kotlin Flow订阅,必须通过catch处理上游异常,且使用生命周期绑定的协程作用域:

lifecycleScope.launch {
    locationService.locationFlow
        .catch { e -> Log.e("FlowError", "定位流异常", e) }
        .collect { location ->
            NotificationManager.showNotification(location)
        }
}

3. 控制LocationService的异常传递

LocationService中不要直接抛出未处理的异常,而是将异常转换为状态返回:

object LocationService {
    fun getCurrentLocation(): LocationData {
        return try {
            // 定位逻辑
            LocationData.Available(/* 定位数据 */)
        } catch (e: SecurityException) {
            LocationData.Unavailable("定位权限不足")
        } catch (e: Exception) {
            LocationData.Unavailable("定位失败: ${e.message}")
        }
    }
}

4. 全局兜底处理(可选)

为避免遗漏,可在Application中设置全局协程异常处理器:

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        val globalCoroutineHandler = CoroutineExceptionHandler { _, e ->
            Log.e("GlobalCoroutineError", "未捕获的协程异常", e)
        }
        // 全局协程作用域使用该处理器
        GlobalScope.launch(globalCoroutineHandler) {
            // 全局协程逻辑
        }
    }
}

重点排查点

  • 检查观察者所在组件(如Activity/Fragment)销毁后,上游是否仍在发送数据/异常
  • 确认所有Flow/LiveData的上游逻辑都添加了异常处理,没有直接抛出未捕获的异常
  • 查看Observer的onChanged方法中是否有潜在崩溃点(如空指针、类型转换异常)

内容的提问来源于stack exchange,提问作者Francisco Torres

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 05:30:47