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

OkHttp3获取ByteArray存入Room时触发IllegalStateException: closed错误

问题描述

使用OkHttp3库从网络下载多个文件,通过response.body?.bytes()获取响应体的ByteArray并存入Room数据库,相关代码如下:

try {
    val request = okhttp3.Request.Builder()
        .url(url)
        .build()
    val response = httpClient.newCall(request).execute()

    fileDao.add(
        FileDatabaseEntity(
            domain = url,
            value = response.body?.bytes() ?: ByteArray(0),
        )
    )
} catch (e: Exception) {
    AppLogger.tag(TAG).e("Processing $url| Error: $e")
}

数据库实体类定义:

@Entity(tableName = FILE)
class FileDatabaseEntity(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = ID)
    val id: Long = 0,

    @ColumnInfo(name = DOMAIN)
    val domain: String,

    @ColumnInfo(name = VALUE, typeAffinity = ColumnInfo.BLOB)
    var value: ByteArray,
) {
    companion object {
        const val FILE = "file"
        const val ID = "id"
        const val DOMAIN = "domain"
        const val VALUE = "value"
    }
}

调用@Insert注解的add方法存入对象时,捕获到java.lang.IllegalStateException: closed错误。但直接传入ByteArray(0)作为value,或把value字段类型改为字符串时均可正常存入,说明数据库配置正常。


问题原因与解决方案

核心原因

  1. 未校验响应状态:当请求返回非成功状态码(如4xx、5xx)时,OkHttp会自动关闭ResponseBody,此时调用bytes()会直接抛出IllegalStateException: closed。
  2. 资源管理不当:Response对象未被正确关闭,可能导致资源泄漏或后续操作中出现状态异常。

修正方案

  1. 先校验响应是否成功:只有当response.isSuccessful为true时,才读取响应体内容;否则直接处理失败逻辑。
  2. 使用use块管理资源:通过use自动关闭Response和ResponseBody,避免资源泄漏,同时确保读取操作在资源有效状态下完成。

修正后的代码如下:

try {
    val request = okhttp3.Request.Builder()
        .url(url)
        .build()
    httpClient.newCall(request).execute().use { response ->
        // 先校验响应是否成功
        val fileBytes = if (response.isSuccessful) {
            response.body?.bytes() ?: ByteArray(0)
        } else {
            ByteArray(0)
        }
        fileDao.add(
            FileDatabaseEntity(
                domain = url,
                value = fileBytes
            )
        )
    }
} catch (e: Exception) {
    AppLogger.tag(TAG).e("Processing $url| Error: $e")
}

额外说明:response.body?.bytes()方法本身会在读取完成后自动关闭ResponseBody,配合use块管理整个Response对象,能彻底避免资源相关的异常问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:05:03