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

使用BottomNavigationView跳转Fragment报java.io.IOException: Canceled如何解决

问题原因
  • 这个OkHttp抛出的java.io.IOException: Canceled是请求被主动取消的典型报错,结合仅从Fragment2跳转Fragment1时才触发的场景,核心原因是Fragment2退出生命周期时,取消了和页面绑定的所有OkHttp请求,但其中部分请求是和Fragment1共用的、或是跳转时刚触发的Fragment1的请求被Fragment2的销毁逻辑误取消了。
  • 结合BottomNavigationView的默认切换逻辑:切换底部导航时,旧Fragment(Fragment2)会先执行onDestroyView/onStop等销毁生命周期,再创建/显示新Fragment(Fragment1)。如果你在Fragment2的销毁回调里写了全局的OkHttp请求取消逻辑(比如调用OkHttpClient.dispatcher.cancelAll()或者不分请求标签全量取消),就会刚好把刚触发的Fragment1的初始化网络请求一起取消,触发报错。而从Fragment3跳转时,Fragment3的销毁逻辑没有做全局取消、或是取消时机和Fragment1的请求时机没有重叠,就不会复现问题。
解决方案
    1. 不要使用全局取消请求的API:禁止在Fragment/Activity的销毁逻辑中调用OkHttpClient.dispatcher.cancelAll(),改为给每个页面的请求添加独立的标签,销毁时仅取消对应标签的请求:
// 给Fragment2的请求添加专属tag
val request = Request.Builder()
    .url("你的接口地址")
    .tag("Fragment2_Request")
    .build()

// Fragment2销毁时仅取消自己页面的请求
override fun onDestroyView() {
    super.onDestroyView()
    okHttpClient.dispatcher.cancelAll { request ->
        request.tag == "Fragment2_Request"
    }
}
    1. 调整BottomNavigationView的Fragment切换生命周期:如果你的导航用的是Jetpack Navigation组件,可以给导航图的Fragment配置android:maxLifecycle="STARTED",切换时仅把旧Fragment回调到onStop不会销毁View,避免销毁逻辑误杀请求。
    1. 增加请求异常捕获:在OkHttp的请求回调处主动捕获Canceled异常,针对这类用户主动取消的请求不需要做错误提示,仅做本地日志记录即可,避免崩溃:
override fun onFailure(call: Call, e: IOException) {
    if (e is IOException && e.message == "Canceled") {
        // 主动取消的请求,不需要处理
        Log.d("OkHttp", "请求已取消")
        return
    }
    // 其他异常正常处理
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:45:03