OkHttp系列十三、OKHttp的Response对象只能使用一次分析

我们在使用OKHttp做网络请求的时候,会发现一个奇怪的现象,那就是Response对象的这个方法:

Response response = client.newCall(requestBuilder.build()).execute();
String s = response.body().string();

只能调用一次,多次调用的时候,会抛出IllegalStateException的异常,这时为什么呢?我们且从源码角度进行分析。

首先是他的前半部分response.body()方法,body()方法的源码如下:

public @Nullable ResponseBody body() {
	return body;
}

可以看出body()方法内部除了返回一个body对象外,并没有做其他的任何处理,理论上这里不存在抛出任何异常的可能。

我们接着往下看他的下一个方法:

response.body().string();

他的源码结构如下:

public final String string() throws IOException {
	BufferedSource source = source();
	try {
		Charset charset = Util.bomAwareCharset(source, charset());
		return source.readString(charset);
	} finally {
		Util.closeQuietly(source);
	}
}

这里,整个方法都是围绕着source 这个变量展开的。可以确定他是这个方法的核心,也是我们要分析的一个关键。

第二行代码很简单,就是获得一个source 对象。继续看第四行代码:

Charset charset = Util.bomAwareCharset(source, charset());

就是将我们的source对象转化为char字符串,源码如下:

	public static Charset bomAwareCharset(BufferedSource source, Charset charset) throws IOException {
	    if (source.rangeEquals(0, UTF_8_BOM)) {
	      source.skip(UTF_8_BOM.size());
	      return UTF_8;
	    }
	    if (source.rangeEquals(0, UTF_16_BE_BOM)) {
	      source.skip(UTF_16_BE_BOM.size());
	      return UTF_16_BE;
	    }
	    if (source.rangeEquals(0, UTF_16_LE_BOM)) {
	      source.skip(UTF_16_LE_BOM.size());
	      return UTF_16_LE;
	    }
	    if (source.rangeEquals(0, UTF_32_BE_BOM)) {
	      source.skip(UTF_32_BE_BOM.size());
	      return UTF_32_BE;
	    }
	    if (source.rangeEquals(0, UTF_32_LE_BOM)) {
	      source.skip(UTF_32_LE_BOM.size());
	      return UTF_32_LE;
	    }
	    return charset;
	}

这里面没有什么特别的操作,也没发现值得特别关注的地方。

我们再看最后可能出现跑异常的地方:finally关键字里面的部分:

Util.closeQuietly(source);

源码如下:

	public static void closeQuietly(Closeable closeable) {
	    if (closeable != null) {
		    try {
	   			closeable.close();
		    } catch (RuntimeException rethrown) {
		    	throw rethrown;
		    } catch (Exception ignored) {
		    }
	    }
	}

看到这里,不知道你有没有发现什么关键的信息,反正笔者是瞬间注意到了这个关键的代码:

	closeable.close();

也就是说,我们在调用一次response.body().string();后,Response就把closeable给关闭了;当我们再次调用这个方法的时候,closeable为空值,就如数据库里面consor游标指针被关闭了一样。之所以要关闭它主要是为了防止无用的多余的I/O操作浪费资源,防止内存泄漏;

因此response.body().string()方法只能调用一次。
这里要注意下,我们讲的是string() 方法,是string() 方法,是string() 方法,大家不要误解为
toString()方法,将对象转化为String字符串的toString方法陷入不存在前述存在的问题。这里我们不多讲了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值