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

Android解压服务器返回Zip文件报java.net.SocketException: Socket closed错误

问题定位与解决

核心错误原因

  • 你在读取到第一个符合命名规则的ZipEntry后就直接调用了zin.close()关闭了整个Zip流,但是while循环还会继续执行zin.nextEntry尝试读取下一个压缩条目,此时底层关联的Socket流已经被提前关闭,就会抛出Socket closed异常。
  • 额外隐患:你嵌套了两层GlobalScope,内层协程执行的时候,外层的OkHttp回调有可能提前释放响应资源,也会触发流提前关闭的问题。
  • 逻辑错误:zin.close()不应该放在循环内部,应该等所有压缩条目都处理完成之后再关闭整个流,否则只能处理第一个符合要求的文件,后续条目都无法读取。

修正后的代码

private fun getImageFromAPI(item: MetaDataEntity, action: (ImagesEntity) -> Unit) {
    GlobalScope.launch(dispatcherProvider.io()) {
        dataHandler.adminRequestHandler.getAdminZipImage(item.uuid) { responseZip: Response ->
            // 先校验响应体非空,避免空指针
            val responseBody = responseZip.body() ?: return@getAdminZipImage
            // use关键字会在代码块执行完成后自动关闭流,无需手动调用close
            responseBody.byteStream().use { inputStream ->
                ZipInputStream(inputStream).use { zin ->
                    var ze: ZipEntry?
                    while (zin.nextEntry.also { ze = it } != null) {
                        ze?.let { entry ->
                            if (validateImageName(entry.name)) {
                                val imageByteArray: ByteArray = zin.readBytes()
                                action(ImagesEntity(item.uuid, item.name, entry.name.substring(0, 3), imageByteArray))
                                // 仅关闭当前压缩条目,不关闭整个Zip流
                                zin.closeEntry()
                            }
                        }
                    }
                }
            }
        }
    }
}

优化点说明

  • 移除了不必要的内层GlobalScope嵌套,避免协程调度导致的响应资源提前释放问题
  • 使用Kotlin内置的use关键字自动管理流的生命周期,无论是否出现异常都会正常关闭资源,避免内存泄漏
  • 仅在循环内部关闭当前处理完成的压缩条目,保留流的开启状态读取后续条目
  • 增加了响应体非空校验,避免空指针崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 06:39:02