起因
对于广大AndroID开发者来说,最近用的最多的网络库,莫过于Okhttp啦(Retrofit依赖Okhttp)。
Okhttp不像SDK内置的httpUrlConnection一样,可以明确的获取数据读写的过程,我们需要执行一些 *** 作。
介绍
Retrofit依赖Okhttp、Okhttp依赖于Okio。那么Okio又是什么鬼?别急,看官方介绍:
Okio is a library that complements java.io and java.nio to make it much easIEr to access,store,and process your data.
翻译过来就是,Okio是一个实现了java.io和java.nio的一个类库,它让连接,存储,处理你的数据更加轻松~(Okio既是读写相关类库,获取进度要从Okio入手)。
好吧,对于广大开发者来说,内心是这样的:TM又要看你文档和用例,按你规则走,轻松个毛啊!
其实,读下API,看下Example熟悉后,人家设计的还是很棒哒。
废话不多说,先看效果。
效果
实际代码:
//添加下载拦截器(this参数是实现下载进度接口的对象) mDownClIEnt = new OkhttpClIEnt.Builder() //只需要一行代码就行了 .addNetworkInterceptor(new DownloadInterceptor(this)) .build(); //添加上传拦截器(this参数是实现上传回调接口的对象) mUploadClIEnt = new OkhttpClIEnt.Builder() //只需要一行代码就行了 .addNetworkInterceptor(new UploadInterceptor(this)) .build();
你只需要一行代码是不行的!我为什么行?因为这是我写的封装类库啊~(最后放地址)
思路
Okhttp依赖Okio进行了数据的读写动作,我们需要找到Okio进行处理。那么,如何加上呢?
Okhttp可以添加Interceptor(拦截器),我们可以通过拦截器的接口方法,获取对应的responseBody、requestbody对象进行 *** 作。然后我们就获取了读写相关的实现方法。具体实现是通过Source、Sink对象。
Source官方解释:SupplIEs a stream of bytes. Use this interface to read data from wherever it's located。
Sink官方解释:Receives a stream of bytes. Use this interface to write data wherever it's needed。
一句话概括:Source对象是对输入流的包装(下载读数据),Sink是对输出流的包装(写数据上传)。
实现
根据需要添加下载、上传Interceptor
//添加下载拦截器(this参数是实现下载进度接口的对象) mDownClIEnt = new OkhttpClIEnt.Builder() .addNetworkInterceptor(new DownloadInterceptor(this)) .build(); //添加上传拦截器(this参数是实现上传回调接口的对象) mUploadClIEnt = new OkhttpClIEnt.Builder() .addNetworkInterceptor(new UploadInterceptor(this)) .build();
拦截器具体实现
//下载拦截器 public class DownloadInterceptor implements Interceptor {private OnDownloadListener mListener;public DownloadInterceptor( OnDownloadListener Listener) { mListener = Listener;}@OverrIDepublic Response intercept(Chain chain) throws IOException { //封装ressponse对象 Response response = wrapResponse(chain.proceed(chain.request())); return response;}private Response wrapResponse(Response response) { if (response == null || response.body() == null) { return response; } //获取处理后的response对象 Response wrapResponse = getWrapResponse(response); return wrapResponse;}private Response getWrapResponse(Response response) { ProgressInfo info = new ProgressInfo(); info.setTime(System.currentTimeMillis()+""); info.setUrl(response.request().url().toString()); Response.Builder builder = response.newBuilder(); //封装responseBody,传入相关参数,获取进度数据回调 return builder.body(new WrapResponseBody(response.body(),info,mListener)).build();}} --------------------------------------分割--------------------------------------- //上传拦截器 public class UploadInterceptor implements Interceptor {private OnUploadListener mListener;public UploadInterceptor(OnUploadListener Listener) { mListener = Listener;}@OverrIDepublic Response intercept(Chain chain) throws IOException { //封装request对象 Request request = wrapRequest(chain.request()); Response response = chain.proceed(request); return response;}private Request wrapRequest(Request request) { if (request == null || request.body() == null) { return request; } Request.Builder builder = request.newBuilder(); ProgressInfo info = new ProgressInfo(); httpUrl url = request.url(); info.setUrl(url.toString()); info.setTime(System.currentTimeMillis()+""); //封装requestbody,传入参数,获取数据进度回调 builder.method(request.method(),new WrapRequestbody(request.body(),mListener)); return builder.build(); } }responseBody、requestbody相关实现//继承ResponseBody实现具体方法public class WrapResponseBody extends ResponseBody {private Handler mHandler = new Handler(Looper.getMainLooper());private ResponseBody mResponseBody;private OnDownloadListener mListener;private ProgressInfo mInfo;private BufferedSource mBufferedSource;private boolean mDoProgress;//传入进度,以及监听对象public WrapResponseBody(ResponseBody responseBody,ProgressInfo info,OnDownloadListener Listener) { mResponseBody = responseBody; mInfo = info; mListener = Listener;}@Nullable@OverrIDepublic MediaType ContentType() { //接口方法,返回类型 return mResponseBody.ContentType();}@OverrIDepublic long contentLength() { long contentLength = mResponseBody.contentLength(); //Gzip压缩格式会返回-1,目前处理是在请求头信息指定("Accept-EnCoding","IDentity")表示不压缩 if (contentLength == -1) { mDoProgress = false; mHandler.post(new Runnable() { @OverrIDe public voID run() { //切换线程,进行失败回调 mListener.onDownLoadGetContentLengthFail(mInfo); } }); } else { mDoProgress = true; } return contentLength;}@OverrIDepublic BufferedSource source() { //WrapSource(继承ForwardingSource,ForwardingSource实现了Source接口) if (mBufferedSource == null) { mInfo.setContentLength(contentLength()); //传入参数,读取具体进度信息,并回调 WrapSource wrapSource = new WrapSource(mResponseBody.source(),mInfo,mListener,mDoProgress); mBufferedSource = Okio.buffer(wrapSource); } return mBufferedSource;}}--------------------------------------分割--------------------------------------- //继承Resquestbody实现具体方法public class WrapRequestbody extends Requestbody {private Requestbody mRequestbody;private OnUploadListener mListener;private ProgressInfo mInfo;private boolean mDoProgress;private Handler mHandler = new Handler(Looper.getMainLooper()); //传入进度,以及监听对象public WrapRequestbody(Requestbody requestbody,OnUploadListener Listener) { mRequestbody = requestbody; mListener = Listener; mInfo = info;}@OverrIDepublic MediaType ContentType() { //接口方法,返回类型 return mRequestbody.ContentType();}@OverrIDepublic long contentLength() throws IOException { try { //上传内容长度,有异常走failWrok处理 long l = mRequestbody.contentLength(); mDoProgress = true; return l; } catch (IOException e) { e.printstacktrace(); failWork(); return -1; }}//进行失败处理private voID failWork() { mDoProgress = false; mHandler.post(new Runnable() { @OverrIDe public voID run() { //切换线程,回调失败信息 mListener.onUploadGetContentLengthFail(mInfo); } });}@OverrIDepublic voID writeto(BufferedSink sink) throws IOException { mInfo.setContentLength(contentLength()); // WrapSink (继承ForwardingSink,ForwardingSink实现了Sink接口) ///传入参数,读取具体进度信息,并回调 WrapSink wrapSink = new WrapSink(sink,mDoProgress); BufferedSink buffer = Okio.buffer(wrapSink); mRequestbody.writeto(buffer); buffer.flush();}}WrapSource、WrapSink相关实现//继承ForwardingSource 实现具体方法public class WrapSource extends ForwardingSource {private Handler mHandler = new Handler(Looper.getMainLooper());private Source mSource;private ProgressInfo mInfo;private OnDownloadListener mListener;private boolean mDoProgress;public WrapSource(Source source,OnDownloadListener Listener,boolean doProgress) { //传入源Source、进度信息、监听进度等信息。 super(source); mSource = source; mInfo = info; mListener = Listener; //传入是否继续执行回调boolean参数,如果之前执行有异常,则不再继续执行回调 mDoProgress = doProgress;}@OverrIDepublic long read(Buffer sink,long byteCount) throws IOException { //获取具体进度信息,来到了熟悉的具体IO long read = super.read(sink,byteCount); if (read != -1) { long l = mInfo.getCurrentLength() + read; mInfo.setCurrentLength(l); mHandler.post(new Runnable() { @OverrIDe public voID run() { if (mDoProgress) { //切换到主线程,回调数据 mListener.onDownLoadProgress(mInfo); } } }); } return read;}}--------------------------------------分割---------------------------------------//继承ForwardingSink 实现具体方法public class WrapSink extends ForwardingSink {private Handler mHandler = new Handler(Looper.getMainLooper());public OnUploadListener mListener;public ProgressInfo mInfo;public boolean mDoProgress;public WrapSink(Sink delegate,OnUploadListener Listener,boolean doProgress) { //传入源Source、进度信息、监听进度等信息。 super(delegate); mInfo = info; mListener = Listener; //传入是否继续执行回调boolean参数,如果之前执行有异常,则不再继续执行回调 mDoProgress = doProgress;}@OverrIDepublic voID write(Buffer source,long byteCount) throws IOException { super.write(source,byteCount); //获取具体进度信息,来到了熟悉的具体IO long l = mInfo.getCurrentLength() + byteCount; mInfo.setCurrentLength(l); mHandler.post(new Runnable() { @OverrIDe public voID run() { if (mDoProgress) { //切换到主线程,回调数据 mListener.onUpLoadProgress(mInfo); } } });}}
总结
以上就是具体的流程了,按照步骤其实很简单。大家了解下挺好的,我这边也封装好了具体的类库和Demo,大家可以直接依赖(查看README.md,使用简单)。
地址:https://github.com/HoldMyOwn/TNetProgress
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
以上是内存溢出为你收集整理的Okhttp、Retrofit进度获取的方法(一行代码搞定)全部内容,希望文章能够帮你解决Okhttp、Retrofit进度获取的方法(一行代码搞定)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)