android 截取一行,Okhttp、Retrofit进度获取的方法(一行代码搞定)

起因

对于广大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熟悉后,人家设计的还是很棒哒。

废话不多说,先看效果。

效果

f8d5b8bd52bf647838e345645197e6a1.gif

实际代码:

//添加下载拦截器(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;

}

@Override

public 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;

}

@Override

public 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(),info,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

@Override

public MediaType contentType() {

//接口方法,返回类型

return mResponseBody.contentType();

}

@Override

public 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;

}

@Override

public 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, ProgressInfo info, OnUploadListener listener) {

mRequestBody = requestBody;

mListener = listener;

mInfo = info;

}

@Override

public MediaType contentType() {

//接口方法,返回类型

return mRequestBody.contentType();

}

@Override

public 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);

}

});

}

@Override

public void writeTo(BufferedSink sink) throws IOException {

mInfo.setContentLength(contentLength());

// WrapSink (继承ForwardingSink,ForwardingSink实现了Sink接口)

///传入参数,读取具体进度信息,并回调

WrapSink wrapSink = new WrapSink(sink, mInfo, mListener, 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, ProgressInfo info, OnDownloadListener listener, boolean doProgress) {

//传入源Source、进度信息、监听进度等信息。

super(source);

mSource = source;

mInfo = info;

mListener = listener;

//传入是否继续执行回调boolean参数,如果之前执行有异常,则不再继续执行回调

mDoProgress = doProgress;

}

@Override

public 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, ProgressInfo info, OnUploadListener listener, boolean doProgress) {

//传入源Source、进度信息、监听进度等信息。

super(delegate);

mInfo = info;

mListener = listener;

//传入是否继续执行回调boolean参数,如果之前执行有异常,则不再继续执行回调

mDoProgress = doProgress;

}

@Override

public 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,使用简单)。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值