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字段类型改为字符串时均可正常存入,说明数据库配置正常。
问题原因与解决方案
核心原因
- 未校验响应状态:当请求返回非成功状态码(如4xx、5xx)时,OkHttp会自动关闭ResponseBody,此时调用
bytes()会直接抛出IllegalStateException: closed。 - 资源管理不当:Response对象未被正确关闭,可能导致资源泄漏或后续操作中出现状态异常。
修正方案
- 先校验响应是否成功:只有当
response.isSuccessful为true时,才读取响应体内容;否则直接处理失败逻辑。 - 使用
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
相关产品推荐
相关产品推荐

