ApolloClient watch方法异常无法捕获?原因及捕获方案
Apollo Watch方法异常捕获问题解析
问题场景
手动执行查询时,因错误服务器地址抛出的异常能被外层try/catch捕获:
try { val response = apolloClient.query(MyQuery()).execute() } catch (e: Exception) { Timber.e("exception from manual execution") Timber.e(e) }
但使用watch()方法执行相同查询时,外层try/catch无法捕获异常:
try { apolloClient.query(MyQuery()) .watch() // 返回Flow .collect { response -> Timber.i("apollo watch collect called") } } catch (e: Exception) { Timber.e("exception from watch execution") Timber.e(e) }
问题根源
execute()是同步阻塞调用,所有异常都会直接在当前线程抛出,外层try/catch可以直接捕获。watch()返回的是Flow类型,属于冷流,其异常传播规则和同步调用不同:流内部的异常不会直接抛到collect所在的外层代码中,而是被封装在流的发射逻辑里,外层的try/catch无法感知到流内部的异常。
正确捕获watch异常的方案
方案1:处理Response中的业务错误
Apollo的watch返回的Flow会优先发射包含错误信息的Response对象(而非直接抛异常),可以先判断Response状态:
apolloClient.query(MyQuery()) .watch() .collect { response -> if (response.hasErrors()) { Timber.e("GraphQL请求错误: ${response.errors}") } else { Timber.i("apollo watch collect called") // 处理正常返回数据 } }
方案2:使用Flow的异常处理操作符捕获底层异常
如果是网络连接失败这类严重底层异常,需要用Flow的catch操作符捕获:
apolloClient.query(MyQuery()) .watch() .catch { e -> Timber.e("watch执行异常") Timber.e(e) } .collect { response -> if (!response.hasErrors()) { Timber.i("apollo watch collect called") } }
方案3:在collect内部嵌套try/catch(不推荐)
也可以在collect的lambda中直接捕获异常,但这种方式不够优雅,适合简单场景:
apolloClient.query(MyQuery()) .watch() .collect { response -> try { if (!response.hasErrors()) { Timber.i("apollo watch collect called") } } catch (e: Exception) { Timber.e(e) } }
内容的提问来源于stack exchange,提问作者me.at.coding
相关产品推荐
相关产品推荐

