OKHttp源码分析(三)之ResponseBody
2017-05-06 12:55
288 查看
一,概述
在使用OKHttp访问网络时,无论是同步请求还是异步请求,返回结果都是Response对象,所有的数据都封装在这个对象中。这个对象常用的方法有:
int code = response.code();//获取响应码 String message = response.message();//获取响应消息 ResponseBody body = response.body();//获取响应体 InputStream inputStream = body.byteStream();//获取输入流 byte[] bytes = body.bytes();//获取字节数组 String str = body.string();//获取字符串数据
响应码和响应消息很简单,这里不做介绍了,下面主要看response的body方法。
response的body方法返回ResponseBody对象,从ResponseBody对象中可以获取到流,字节数组,字符串等类型的数据。下面重点讲解ResponseBody对象是如何创建的,是怎么从ResponseBody对象中获取到不同数据的。
二,ResponseBody对象的创建
看源码可知,ResponseBody类是一个抽象类,不能被实例化。一般使用它的子类RealResponseBody实例化对象。RealResponseBody类的构造方法 源码如下:
public RealResponseBody(Headers headers, BufferedSource source) { this.headers = headers; this.source = source; }
由此可知,在创建RealResponseBody对象时,传递了BufferedSource 对象,BufferedSource 是okio库中的输入流,这里就当作inputStream来使用。
注意:这个BufferedSource 对象很重要,它是网络请求成功后返回的流对象,所有的数据都要从这个流中获取。
在RealResponseBody类中字段source 是私有的,所以需要提供对外访问的公共方法,如下:
@Override public BufferedSource source() { return source; }
总结:在创建ResponseBody时,传递过来一个流对象。
三,从ResponseBody中获取输入流对象
从ResponseBody中获取输入流对象的代码是:InputStream inputStream = body.byteStream();//获取输入流
ResponseBody类的byteStream方法的原码是:
public final InputStream byteStream() { return source().inputStream(); }
这个代码很简单,首先调用source方法返回BufferedSource 对象,BufferedSource 就是封装的inputStream,所以可以从,BufferedSource对象中获取inputStream对象。
三,从ResponseBody中获取字节数组
从ResponseBody中获取字节数组的代码是:byte[] bytes = body.bytes();//获取字节数组
ResponseBody类的bytes方法的原码是:
public final byte[] bytes() throws IOException { long contentLength = contentLength(); BufferedSource source = source(); byte[] bytes; try { bytes = source.readByteArray(); } finally { Util.closeQuietly(source); } return bytes; }
源码中首先调用的是source方法,source方法返回BufferedSource 对象。然后调用BufferedSource 的readByteArray方法返回字节数组。
四,从ResponseBody中获取字符串数据
从ResponseBody中获取字符串数据的方法:String str = body.string();//获取字符串数据
ResponseBody类的string方法的原码是:
public final String string() throws IOException { return new String(bytes(), charset().name()); }
这个方法比较简单,先调用bytes方法得到字节数组,再将字节数组转换为字符串。
五,OKHttp中实现文件下载
分析ResponseBody类的原码发现:OKHttp并没有提供下载文件放方法。在httpURLconnection中下载文件时是先得到输入流对象,然后从输入流对象中读取数据得到文件对象。在OKHttp中也能得到流对象,所以也可以自己实现文件下载,下载代码如下:try{ InputStream is = response.body().byteStream();//从服务器得到输入流对象 long sum = 0; File dir = new File(mDestFileDir); if (!dir.exists()){ dir.mkdirs(); } File file = new File(dir, mdestFileName);//根据目录和文件名得到file对象 FileOutputStream fos = new FileOutputStream(file); byte[] buf = new byte[1024*8]; int len = 0; while ((len = is.read(buf)) != -1){ fos.write(buf, 0, len); } fos.flush(); return file; }
五,注意要点
从上面的分析可知,ResponseBody类的源码是非常简单的。本质就是从输入流中获取数据,但在初次使用时遇到了很多问题,现在总结如下:在解析ResponseBody前ResponseBody中仅仅有流对象,调用string方法时才开始解析流对象,所以这一步操作仍然需要与服务器有联系,仍然属于访问服务器的范畴,所以必须放在子线程中。只有得到String对象后才能跳转到UI线程修改UI。
在解析ResponseBody前ResponseBody中仅仅有流对象,调用string方法就是从输入流中读取数据,这行代码执行完毕表示读取完毕。而此时再次调用string方法就得不到数据了。同理bytes方法也是从输入流中读取数据,所以调用string方法后再次调用bytes方法也得不到数据。
从ResponseBody的byteStream方法中得到inputstream对象时,并没有从输入流中读取数据,此时仍然可以从string方法中获取到数据。但是获取string数据后,inputstream对象仍存在,但里面已经没有数据了。
相关文章推荐
- OkHttp3源码分析
- OkHttp源码分析之基本框架2
- Android 源码分析之okhttp3(builder二)
- OkHttp源码分析(一)
- Okhttp3的源码分析_小白看源码
- Okhttp源码简单分析(完善ing)
- OKHttp源码分析
- OKHttp源码分析(二)之RequestBody
- Okhttp文件上传源码分析
- 【精】OkHttp3源码分析[综述]
- Android 4.4以上使用HttpURLConnection底层使用OkHttp实现的源码分析
- Okhttp源码分析-流程分析(1)-基于最新okhttp3.4.1
- OKHttp源码分析2 - Request的创建和发送
- OkHttp3源码分析[任务队列]
- OkHttp源码分析
- OkHttp源码分析之基本框架1
- OkHttp3源码分析[缓存策略]
- OKHttp框架源码分析(一)
- OKHttp源码分析
- 重识OkHttp:从深入了解到源码分析