OkHttp 使用详情二

来源:互联网 发布:手机版设计软件 编辑:程序博客网 时间:2024/06/05 16:39

一概要:

OkHttp,作为当下最流行的网络请求方式,是非常方便且高效的。但是如果现在有个需求,上传和

下载文件并且在过程中给用户提供友好的界面提示(提示用户下载的进度)。似乎没方法用简单的

OkHttp API来实现。网上搜索了一个下,找到一个一些方法。在证明确实可行之后。在此归纳总结

出这篇博客。

(OkHttp的基本使用,请参考:OkHttp 使用详情一)


二实现

1,文件的下载进度监听

# 编写ProgressResponseListener接口,定义回调方法onResponseProgress(longbytesRead,longcontentLength,booleandone)

# 编写ProgressResponseBody继承ResponseBody,并且在source方法中实时的回调接口的回调方法。
# 为OkHttpClient添加拦截器Interceptor,在拦截器中将原本ResponseBody封装成自定义的ProgressResponseBody。
自定义接口ProgresResponseListener
/** * 响应进度回调接口,用于文件下载 * Created by SongbinWang on 2017/7/6. */public interface ProgressResponseListener {    void onResponseProgress(long bytesRead, long contentLength, boolean done);}
封装ResponseBody
package com.wang.csdnapp.okhttp;import android.support.annotation.Nullable;import com.wang.csdnapp.util.LogUtil;import java.io.IOException;import okhttp3.MediaType;import okhttp3.ResponseBody;import okio.Buffer;import okio.BufferedSource;import okio.ForwardingSource;import okio.Okio;import okio.Source;/** * Created by SongbinWang on 2017/7/6. */public class ProgressResponseBody extends ResponseBody{    private static final String TAG = "ProgressResponseBody";    //待包装的响应    private ResponseBody responseBody;    private ProgressResponseListener responseListener;    private BufferedSource bufferedSource;    public ProgressResponseBody(ResponseBody responseBody, ProgressResponseListener responseListener){        this.responseBody = responseBody;        this.responseListener = responseListener;    }    @Override    public MediaType contentType() {        return responseBody.contentType();    }    @Override    public long contentLength() {        return responseBody.contentLength();    }    @Override    public BufferedSource source() {        if(bufferedSource == null){            //包装            bufferedSource = Okio.buffer(source(responseBody.source()));        }        return bufferedSource;    }    private Source source(Source source){        return new ForwardingSource(source) {            long totalByteRead = 0l;            @Override            public long read(Buffer sink, long byteCount) throws IOException {                long byteRead = super.read(sink, byteCount);                //增加当前读取的字节,如果读取完成,byteRead = -1                totalByteRead += (byteRead == -1 ? 0 : byteRead);                //回调,如果responseBody.contentLength 不知道 返回-1                LogUtil.i(TAG, "totalByteRead:" + totalByteRead + ",byteRead:" + byteRead                        + ",contentLength:" + responseBody.contentLength());                responseListener.onResponseProgress(totalByteRead,                        responseBody.contentLength(), byteRead == -1);                return byteRead;            }        };    }}
添加拦截器
    /**     * 包装OkHttpClient用于下载文件     * @param responseListener     * @return     */    public static OkHttpClient addProgressResponseListener(            final ProgressResponseListener responseListener){        OkHttpClient okHttpClient = new OkHttpClient.Builder()                .connectTimeout(30, TimeUnit.SECONDS)                .readTimeout(60*60, TimeUnit.SECONDS)                .writeTimeout(60*60, TimeUnit.SECONDS)                //添加拦截器                .addInterceptor(new Interceptor() {                    @Override                    public Response intercept(Chain chain) throws IOException {                        //拦截                        Response originalResponse = chain.proceed(chain.request());                        //包装响应体并返回                        return originalResponse.newBuilder()                                .body(new ProgressResponseBody(originalResponse.body(), responseListener))                                .build();                    }                })                .build();        return okHttpClient;    }
2,文件上传进度监听
# 编写接口ProgressRequestListener,并定义回调方法onRequestProgress(long bytesWritten, long contentLength, boolean done);
# 编写ProgressRequestBody继承RequestBody,并在sink方法中实时调用接口ProgressRequestListener的回调方法。
# 将RequestBody替换成ProgressRequestBody。
自定义接口ProgressRequestListener:
/** * 请求进度回调接口,用于文件上传 * Created by SongbinWang on 2017/7/6. */public interface ProgressRequestListener {    void onRequestProgress(long bytesWritten, long contentLength, boolean done);}
自定义封装RequestBody
package com.wang.csdnapp.okhttp;import java.io.IOException;import okhttp3.MediaType;import okhttp3.RequestBody;import okio.Buffer;import okio.BufferedSink;import okio.ForwardingSink;import okio.Okio;import okio.Sink;/** * Created by SongbinWang on 2017/7/6. */public class ProgressRequestBody extends RequestBody{    private RequestBody requestBody;    private ProgressRequestListener requestListener;    private BufferedSink bufferedSink;    public ProgressRequestBody(RequestBody requestBody, ProgressRequestListener requestListener) {        this.requestBody = requestBody;        this.requestListener = requestListener;    }    @Override    public MediaType contentType() {        return requestBody.contentType();    }    @Override    public long contentLength() throws IOException {        return requestBody.contentLength();    }    @Override    public void writeTo(BufferedSink sink) throws IOException {        if(bufferedSink == null){            //包装            bufferedSink = Okio.buffer(sink(sink));        }        //写入        requestBody.writeTo(bufferedSink);        //必须调用flush 否侧最后一部分,不会写入        bufferedSink.flush();    }    /**     * 写入包装,回调进度接口     * @param sink     * @return     */    private Sink sink(Sink sink){        return new ForwardingSink(sink){            //当前写入的总字节数            private long totalWrite = 0l;            //整个文件的总大小            private long contentLength = 0l;            @Override            public void write(Buffer source, long byteCount) throws IOException {                super.write(source, byteCount);                if(contentLength == 0){                    //获得之后,不再调用                    contentLength = requestBody.contentLength();                }                //增加总写入的字节数                totalWrite += byteCount;                //回调                requestListener.onRequestProgress(totalWrite,                        contentLength, totalWrite == contentLength);            }        };    }}

三使用
首先文件上传非常的简单,只要不RequestBody替换成我们封装好了的ProgressRequestBody(带
ProgressRequestListener)。
下面是下载的使用验证(编写一个DownloadService,启动Service就会执行下载操作):
import android.app.Service;import android.content.Intent;import android.os.IBinder;import com.wang.csdnapp.okhttp.ProgressHelper;import com.wang.csdnapp.okhttp.ProgressResponseListener;import com.wang.csdnapp.util.LogUtil;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;/** * Created by SongbinWang on 2017/7/6. */public class DownloadService extends Service implements ProgressResponseListener{    private static final String TAG = "DownloadService";    //工作线程中执行耗时的网络请求    Thread thread = null;    private OkHttpClient okHttpClient = ProgressHelper.addProgressResponseListener(this);//添加了拦截器    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        LogUtil.i(TAG, "onStartCommand current Thread:" + Thread.currentThread());        thread = new Thread(){            @Override            public void run() {                //要下载的文件,这里是一张图片                String url = "http://g.hiphotos.baidu.com/zhidao/pic/item/18d8bc3eb13533fa746b1558aed3fd1f40345be3.jpg";                LogUtil.i(TAG, "url:" + url);                Request request = new Request.Builder().url(url).build();                InputStream in = null;                FileOutputStream fos = null;                try {                    String path = "mnt/sdcard/Download/qq.jpg";//下载的后文件的路径和名称                    File file = new File(path);                    LogUtil.i(TAG, "loacal path:" + file.getAbsolutePath());                    Response response = okHttpClient.newCall(request).execute();//同步执行                    if(response.isSuccessful()){                        LogUtil.i(TAG, "response successfull!");                        in = response.body().byteStream();                        fos = new FileOutputStream(file);                        int len = -1;                        byte[] buf = new byte[1024];                        while((len = in.read(buf)) != -1){                            fos.write(buf, 0, len);                        }                    }else{                        LogUtil.i(TAG, "response failiure:" + response);                    }                } catch (IOException e) {                    e.printStackTrace();                }finally {//关闭流对象                    if(in != null){ try{ in.close();}catch (Exception e){}}                    if(fos != null){ try{ fos.close();}catch (Exception e){}}                }            }        };        thread.start();        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        super.onDestroy();    }    @Override    public IBinder onBind(Intent intent) {        return null;    }    //文件下载进度的回调    @Override    public void onResponseProgress(long bytesRead, long contentLength, boolean done) {        LogUtil.i(TAG, "onResponseProgress currentThread: " + Thread.currentThread() );        LogUtil.i(TAG, "onResponseProgress byteRead:" + bytesRead + ",contentLength:" + contentLength + ",done" + done);    }}
注意onResponseProgress的回调是在工作线程中执行的,不能直接更新UI。
参考:http://blog.csdn.net/sbsujjbcy/article/details/48194701

原创粉丝点击