Android异常:ResponseBody.string()导致的OutofMemory、IllegalStateException异常

本文介绍如何处理OKHttp中过大的响应数据以避免内存溢出和非法状态异常,包括使用输入流读取数据的方法及针对大量数据的分批处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

OKHttp中的ResponseBody.string()方法

异常内容如下:IllegalStateException

java.lang.IllegalStateException: closed
            at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSource.read(HttpConnection.java:455)
            at okio.Buffer.writeAll(Buffer.java:594)
            at okio.RealBufferedSource.readByteArray(RealBufferedSource.java:87)
            at com.squareup.okhttp.ResponseBody.bytes(ResponseBody.java:56)
            at com.squareup.okhttp.ResponseBody.string(ResponseBody.java:82)

或者出现OutOfMemory异常

如果采用ResponseBody的string()方法会一次性把数据读取到内存中,如果数据超过1MB可能会报内存溢出,所以对于超过1MB的数据,建议采用流的方式去读取,如ResponseBody的byteStream()方法。

解决方法

public void onResponse(Call call, Response response) throws IOException {
					if (response.isSuccessful()) {
						String bodyInfo = "";
						try {
							ResponseBody body = response.body();
							bodyInfo = inputStream2String(body.byteStream());
							body.close();
						} catch (Exception e) {
							e.printStackTrace();
						}
						Log.d("--HttpClient", "--body:"+bodyInfo);
						callback.onResponse(bodyInfo);
					} else {
						callback.onFailure(response.code());
					}
					
				}

public String inputStream2String(InputStream in) throws IOException {
		StringBuffer out = new StringBuffer();
		byte[] b = new byte[4096];
		for (int n; (n = in.read(b)) != -1;) {
			out.append(new String(b, 0, n));
		}
		return out.toString();
	}  

采用inputStream流的方式读取数据,这样可以避免直接调用string方法引起的OOM异常。
也可避免多次调用string方法引起的IllegalStateException异常。

注意

若onResponse中返回的内容过大,如3万条通讯录的信息,那么虽然通过inputStream读取可以有效避免OOM异常,但是在利用String转Json时,还是容易发生OOM异常,此时的解决方法应该是同服务器方一起修改;数据分批返回,如先返回总条数以及当前的条数,客户端按页来解析,解析完一页则做相应的存储,然后在内存中释放掉该页所占内存,当所有的信息均解析存储完毕,则认为此次任务完成,否则认为此次任务失败。

### 解决 `com.google.gson.JsonSyntaxException` 异常 当遇到 `com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 34 path $.data` 这样的错误时,通常意味着 JSON 数据的结构不符合预期。具体来说,在尝试解析某个字段为对象时,实际接收到的是字符串。 #### 可能的原因 - API 返回的数据格式不匹配定义的对象模型。 - 响应体为空或部分数据丢失。 - 错误处理不当导致异常抛出[^1]。 #### 处理方法 为了有效解决问题并提高代码健壮性,建议采取以下措施: ##### 验证API返回值 确保服务器端返回的有效JSON响应与客户端期望一致。可以通过打印原始HTTP响应来验证这一点: ```java if (response.isSuccessful()) { String responseBody = response.body().string(); Log.d("Response", "Raw Response Body:" + responseBody); } ``` ##### 使用泛型类型进行反序列化 如果不确定具体的类结构或者存在嵌套复杂情况,则可以先将其转换成通用Map形式再进一步操作: ```java Type typeOfHashMap = new TypeToken<HashMap<String, Object>>(){}.getType(); Map<String,Object> map = gson.fromJson(jsonString,typeOfHashMap); // 对map中的元素做相应判断后再转为目标实体bean ``` ##### 设置宽松模式 对于某些特殊情况下的非标准json串(比如未加双引号包裹key),可以在创建gson实例的时候开启lenient选项允许更灵活地解析输入流: ```java GsonBuilder builder = new GsonBuilder(); builder.setLenient(); // 启用宽容模式 Gson gson = builder.create(); OrderRespData orderRespData = gson.fromJson(responseBody, OrderRespData.class); ``` ##### 添加空指针检查 为了避免因网络问题或其他因素造成null值而引发崩溃,应该始终对可能为null的结果执行必要的校验逻辑: ```java if (!TextUtils.isEmpty(responseBody)) { try{ OrderRespData orderRespData = gson.fromJson(responseBody, OrderRespData.class); } catch(JsonSyntaxException e){ // handle exception here... } } else { // Handle empty response body scenario. } ``` 通过上述手段能够显著降低此类异常发生的概率,并增强应用程序面对意外状况的能力[^2]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值