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
相关产品推荐
相关产品推荐

