OkHttp3源码(七) ------ ResponseBody

ResponseBody抽象类 ——主要是对响应正文的概念的实现。
因为ResponseBody抽象类的子类RealResponseBody实现的很简单,就是持有响应头和读取流。其中大部分功能还是在ResponseBody抽象类中的,所以这里只分析ResponseBody。

我们看一下源码。

一、ResponseBody类声明

public abstract class MyResponseBody implements Closeable

可以看到它实现了Closeable接口,这就意味着它是一种占用系统资源的类,所以要记得及时关闭

2、ResponseBody类的属性

//字符流
private Reader reader;

只有一个属性。其实主要的属性是在它的子类中的,它的子类RealResponseBody属性也就是两个。

  private final Headers headers;
  private final BufferedSource source;

所以响应正文的属性还是很少的。

3、实例化ResponseBody抽象类

 public static ResponseBody create(MediaType contentType, String content) {
    Charset charset = UTF_8;
    if (contentType != null) {
      charset = contentType.charset();
      if (charset == null) {
        charset = UTF_8;
        contentType = MediaType.parse(contentType + "; charset=utf-8");
      }
    }
    Buffer buffer = new Buffer().writeString(content, charset);
    return create(contentType, buffer.size(), buffer);
  }

  public static ResponseBody create(final MediaType contentType, byte[] content) {
    Buffer buffer = new Buffer().write(content);
    return create(contentType, content.length, buffer);
  }

 //上面两个方法最终会调用这个方法。
//实例化响应正文,可以看到响应正文的内容是存在缓存区BufferedSource中的
public static ResponseBody create(
final MediaType contentType, final long contentLength, final BufferedSource content) {
if (content == null) throw new NullPointerException("source == null");
return new ResponseBody() {
@Override public MediaType contentType() {
return contentType;
}

@Override public long contentLength() {
return contentLength;
}

@Override public BufferedSource source() {
return content;
}
};
}

通过上面的实例化代码,我们可以看到,响应正文是存放到流中的。这也是为什么我们要及时关闭响应正文的原因。

4、主要方法

//获得响应正文的类型
public abstract MediaType contentType();
//获得响应正文的长度
public abstract long contentLength();
//获得读取流的缓存区
public abstract BufferedSource source();
//获得缓冲区的读取流------字节流
public final InputStream byteStream() {
return source().inputStream();
}
//获得缓存区的读取流------字符流
public final Reader charStream() {
Reader r = reader;
return r != null ? r : (reader = new BomAwareReader(source(), charset()));
}
//通过字节流读取缓存区内容
public final byte[] bytes() throws IOException {
long contentLength = contentLength();
if (contentLength > Integer.MAX_VALUE) {
throw new IOException("Cannot buffer entire body for content length: " + contentLength);
}

BufferedSource source = source();
byte[] bytes;
try {
bytes = source.readByteArray();
} finally {
Util.closeQuietly(source);
}
if (contentLength != -1 && contentLength != bytes.length) {
throw new IOException("Content-Length ("
+ contentLength
+ ") and stream length ("
+ bytes.length
+ ") disagree");
}
return bytes;
}

//通过字符流读取缓存区内容
public final String string() throws IOException {
BufferedSource source = source();
try {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
} finally {
Util.closeQuietly(source);
}
}
//获得响应正文的编码方式------默认为UTF-8
private Charset charset() {
MediaType contentType = contentType();
return contentType != null ? contentType.charset(UTF_8) : UTF_8;
}
//关闭响应正文的缓存区流
@Override public void close() {
Util.closeQuietly(source());
}

5、BomAwareReader类

扫描二维码关注公众号,回复: 2612600 查看本文章
static final class BomAwareReader extends Reader {
//。。。。。。
//。。。。。。
//。。。。。。
}

这是ResponseBody的内部类,主要实现缓冲区的字节流根据特定的编码方式转换为字符流

6、总结
ResponseBody——响应正文的内容是在流中的,所以要获取正文就涉及到IO流的操作(记得关闭资源)
ResponseBody类提供了三种读取IO流内容的方法,
string()通过字符流的方式读取内容
bytes()通过字节流的方式读取内容
我们还可以获得字节流,实现自己的定制化读取。

猜你喜欢

转载自blog.csdn.net/look_Future/article/details/79731608
今日推荐