Android中对OkHttp的封装使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/longxuanzhigu/article/details/82706762

一、OkHttp导包:

    compile 'com.squareup.okhttp3:okhttp:3.4.1'
    compile 'com.squareup.okio:okio:1.9.0'
    compile 'com.google.code.gson:gson:2.3.1'

二、OkHttpUtils封装成工具类:

package com.showly.okhttpdemo.http;

import android.content.Context;
import android.os.Handler;
import com.google.gson.Gson;
import com.showly.okhttpdemo.http.body.ProgressRequestBody;
import com.showly.okhttpdemo.http.body.ResponseProgressBody;
import com.showly.okhttpdemo.http.response.DownloadResponseHandler;
import com.showly.okhttpdemo.http.response.GsonResponseHandler;
import com.showly.okhttpdemo.http.response.IResponseHandler;
import com.showly.okhttpdemo.http.response.JsonResponseHandler;
import com.showly.okhttpdemo.http.response.RawResponseHandler;
import com.showly.okhttpdemo.http.util.LogUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 封装好的OkHttpUtils
 */
public class OkHttpUtils {

    private OkHttpClient client;
    private static OkHttpUtils instance;

    public OkHttpUtils() {
        client = new OkHttpClient();
    }

    /**
     * 获取句柄
     * @return
     */
    public static OkHttpUtils get() {
        if(instance == null) {
            instance = new OkHttpUtils();
        }

        return instance;
    }

    /**
     * post 请求
     * @param url url
     * @param params 参数
     * @param responseHandler 回调
     */
    public void post(final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
        post(null, url, params, responseHandler);
    }

    /**
     * post 请求
     * @param context 发起请求的context
     * @param url url
     * @param params 参数
     * @param responseHandler 回调
     */
    public void post(Context context, final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
        //post builder 参数
        FormBody.Builder builder = new FormBody.Builder();
        if(params != null && params.size() > 0) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }

        Request request;

        //发起request
        if(context == null) {
            request = new Request.Builder()
                    .url(url)
                    .post(builder.build())
                    .build();
        } else {
            request = new Request.Builder()
                    .url(url)
                    .post(builder.build())
                    .tag(context)
                    .build();
        }


        client.newCall(request).enqueue(new MyCallback(new Handler(), responseHandler));
    }

    /**
     * get 请求
     * @param url url
     * @param params 参数
     * @param responseHandler 回调
     */
    public void get(final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
        get(null, url, params, responseHandler);
    }

    /**
     * get 请求
     * @param context 发起请求的context
     * @param url url
     * @param params 参数
     * @param responseHandler 回调
     */
    public void get(Context context, final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
        //拼接url
        String get_url = url;
        if(params != null && params.size() > 0) {
            int i = 0;
            for (Map.Entry<String, String> entry : params.entrySet()) {
                if(i++ == 0) {
                    get_url = get_url + "?" + entry.getKey() + "=" + entry.getValue();
                } else {
                    get_url = get_url + "&" + entry.getKey() + "=" + entry.getValue();
                }
            }
        }

        Request request;

        //发起request
        if(context == null) {
            request = new Request.Builder()
                    .url(url)
                    .build();
        } else {
            request = new Request.Builder()
                    .url(url)
                    .tag(context)
                    .build();
        }

        client.newCall(request).enqueue(new MyCallback(new Handler(), responseHandler));
    }

    /**
     * 上传文件
     * @param url url
     * @param files 上传的文件files
     * @param responseHandler 回调
     */
    public void upload(String url, Map<String, File> files, final IResponseHandler responseHandler) {
        upload(null, url, null, files, responseHandler);
    }

    /**
     * 上传文件
     * @param url url
     * @param params 参数
     * @param files 上传的文件files
     * @param responseHandler 回调
     */
    public void upload(String url, Map<String, String> params, Map<String, File> files, final IResponseHandler responseHandler) {
        upload(null, url, params, files, responseHandler);
    }

    /**
     * 上传文件
     * @param context 发起请求的context
     * @param url url
     * @param files 上传的文件files
     * @param responseHandler 回调
     */
    public void upload(Context context, String url, Map<String, File> files, final IResponseHandler responseHandler) {
        upload(context, url, null, files, responseHandler);
    }

    /**
     * 上传文件
     * @param context 发起请求的context
     * @param url url
     * @param params 参数
     * @param files 上传的文件files
     * @param responseHandler 回调
     */
    public void upload(Context context, String url, Map<String, String> params, Map<String, File> files, final IResponseHandler responseHandler) {
        MultipartBody.Builder multipartBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        //添加参数
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                multipartBuilder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""),
                        RequestBody.create(null, params.get(key)));
            }
        }

        //添加上传文件
        if (files != null && !files.isEmpty()) {
            RequestBody fileBody;
            for (String key : files.keySet()) {
                File file = files.get(key);
                String fileName = file.getName();
                fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                multipartBuilder.addPart(Headers.of("Content-Disposition",
                        "form-data; name=\"" + key + "\"; filename=\"" + fileName + "\""),
                        fileBody);
            }
        }

        Request request;
        if(context == null) {
            request = new Request.Builder()
                    .url(url)
                    .post(new ProgressRequestBody(multipartBuilder.build(),responseHandler))
                    .build();
        } else {
            request = new Request.Builder()
                    .url(url)
                    .post(new ProgressRequestBody(multipartBuilder.build(),responseHandler))
                    .tag(context)
                    .build();
        }

        client.newCall(request).enqueue(new MyCallback(new Handler(), responseHandler));
    }

    /**
     * 下载文件
     * @param url 下载地址
     * @param filedir 下载目的目录
     * @param filename 下载目的文件名
     * @param downloadResponseHandler 下载回调
     */
    public void download(String url, String filedir, String filename, final DownloadResponseHandler downloadResponseHandler) {
        download(null, url, filedir, filename, downloadResponseHandler);
    }

    /**
     * 下载文件
     * @param context 发起请求的context
     * @param url 下载地址
     * @param filedir 下载目的目录
     * @param filename 下载目的文件名
     * @param downloadResponseHandler 下载回调
     */
    public void download(Context context, String url, String filedir, String filename, final DownloadResponseHandler downloadResponseHandler) {

        Request request;
        if(context == null) {
            request = new Request.Builder()
                    .url(url)
                    .build();
        } else {
            request = new Request.Builder()
                    .url(url)
                    .tag(context)
                    .build();
        }

        client.newBuilder()
                .addNetworkInterceptor(new Interceptor() {      //设置拦截器
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Response originalResponse = chain.proceed(chain.request());
                        return originalResponse.newBuilder()
                                .body(new ResponseProgressBody(originalResponse.body(), downloadResponseHandler))
                                .build();
                    }
                })
                .build()
                .newCall(request)
                .enqueue(new MyDownloadCallback(new Handler(), downloadResponseHandler, filedir, filename));
    }

    /**
     * 取消当前context的所有请求
     * @param context
     */
    public void cancel(Context context) {
        if(client != null) {
            for(Call call : client.dispatcher().queuedCalls()) {
                if(call.request().tag().equals(context))
                    call.cancel();
            }
            for(Call call : client.dispatcher().runningCalls()) {
                if(call.request().tag().equals(context))
                    call.cancel();
            }
        }
    }

    //下载回调
    private class MyDownloadCallback implements Callback {

        private Handler mHandler;
        private DownloadResponseHandler mDownloadResponseHandler;
        private String mFileDir;
        private String mFilename;

        public MyDownloadCallback(Handler handler, DownloadResponseHandler downloadResponseHandler,
                                  String filedir, String filename) {
            mHandler = handler;
            mDownloadResponseHandler = downloadResponseHandler;
            mFileDir = filedir;
            mFilename = filename;
        }

        @Override
        public void onFailure(Call call, final IOException e) {
            LogUtils.e("onFailure", e);

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mDownloadResponseHandler.onFailure(e.toString());
                }
            });
        }

        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            if(response.isSuccessful()) {
                File file = null;
                try {
                    file = saveFile(response, mFileDir, mFilename);
                } catch (final IOException e) {
                    LogUtils.e("onResponse saveFile fail", e);

                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mDownloadResponseHandler.onFailure("onResponse saveFile fail." + e.toString());
                        }
                    });
                }

                final File newFile = file;
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mDownloadResponseHandler.onFinish(newFile);
                    }
                });
            } else {
                LogUtils.e("onResponse fail status=" + response.code());

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mDownloadResponseHandler.onFailure("fail status=" + response.code());
                    }
                });
            }
        }
    }

    //callback
    private class MyCallback implements Callback {

        private Handler mHandler;
        private IResponseHandler mResponseHandler;

        public MyCallback(Handler handler, IResponseHandler responseHandler) {
            mHandler = handler;
            mResponseHandler = responseHandler;
        }

        @Override
        public void onFailure(Call call, final IOException e) {
            LogUtils.e("onFailure", e);

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mResponseHandler.onFailure(0, e.toString());
                }
            });
        }

        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            if(response.isSuccessful()) {
                final String response_body = response.body().string();

                if(mResponseHandler instanceof JsonResponseHandler) {       //json回调
                    try {
                        final JSONObject jsonBody = new JSONObject(response_body);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                ((JsonResponseHandler)mResponseHandler).onSuccess(response.code(), jsonBody);
                            }
                        });
                    } catch (JSONException e) {
                        LogUtils.e("onResponse fail parse jsonobject, body=" + response_body);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mResponseHandler.onFailure(response.code(), "fail parse jsonobject, body=" + response_body);
                            }
                        });
                    }
                } else if(mResponseHandler instanceof GsonResponseHandler) {    //gson回调
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Gson gson = new Gson();
                                ((GsonResponseHandler)mResponseHandler).onSuccess(response.code(),
                                        gson.fromJson(response_body, ((GsonResponseHandler)mResponseHandler).getType()));
                            } catch (Exception e) {
                                LogUtils.e("onResponse fail parse gson, body=" + response_body, e);
                                mResponseHandler.onFailure(response.code(), "fail parse gson, body=" + response_body);
                            }

                        }
                    });
                } else if(mResponseHandler instanceof RawResponseHandler) {     //raw字符串回调
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            ((RawResponseHandler)mResponseHandler).onSuccess(response.code(), response_body);
                        }
                    });
                }
            } else {
                LogUtils.e("onResponse fail status=" + response.code());

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mResponseHandler.onFailure(0, "fail status=" + response.code());
                    }
                });
            }
        }
    }

    //保存文件
    private File saveFile(Response response, String filedir, String filename) throws IOException {
        InputStream is = null;
        byte[] buf = new byte[2048];
        int len;
        FileOutputStream fos = null;
        try {
            is = response.body().byteStream();
            File dir = new File(filedir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(dir, filename);
            fos = new FileOutputStream(file);
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            fos.flush();
            return file;
        } finally {
            try {
                if (is != null) is.close();
            } catch (IOException e) {
            }
            try {
                if (fos != null) fos.close();
            } catch (IOException e) {
            }
        }
    }

    //获取mime type
    private String guessMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }
}

涉及的接口及类:

1、 回调父类接口

package com.showly.okhttpdemo.http.response;

/**
 * 回调接口父类
 */
public interface IResponseHandler {

    void onFailure(int statusCode, String error_msg);

    void onProgress(long currentBytes, long totalBytes);
}

2、 字符串结果回调接口

package com.showly.okhttpdemo.http.response;

/**
 * raw 字符串结果回调
 */
public abstract class RawResponseHandler implements IResponseHandler {

    public abstract void onSuccess(int statusCode, String response);

    @Override
    public void onProgress(long currentBytes, long totalBytes) {

    }
}

3.json类型的回调接口

package com.showly.okhttpdemo.http.response;

import org.json.JSONObject;

/**
 * json类型的回调接口
 */
public abstract class JsonResponseHandler implements IResponseHandler {

    public abstract void onSuccess(int statusCode, JSONObject response);

    @Override
    public void onProgress(long currentBytes, long totalBytes) {

    }
}

4.Gson类型的回调接口

package com.showly.okhttpdemo.http.response;

import com.google.gson.internal.$Gson$Types;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Gson类型的回调接口
 */
public abstract class GsonResponseHandler<T> implements IResponseHandler {

    Type mType;

    public GsonResponseHandler() {
        Type myclass = getClass().getGenericSuperclass();    //反射获取带泛型的class
        if (myclass instanceof Class) {
            throw new RuntimeException("Missing type parameter.");
        }
        ParameterizedType parameter = (ParameterizedType) myclass;      //获取所有泛型
        mType = $Gson$Types.canonicalize(parameter.getActualTypeArguments()[0]);  //将泛型转为type
    }

    public final Type getType() {
        return mType;
    }

    public abstract void onSuccess(int statusCode, T response);

    @Override
    public void onProgress(long currentBytes, long totalBytes) {

    }
}

5、下载回调接口

package com.showly.okhttpdemo.http.response;

import java.io.File;

/**
 * 下载回调
 */
public abstract class DownloadResponseHandler {

    public abstract void onFinish(File download_file);
    public abstract void onProgress(long currentBytes, long totalBytes);
    public abstract void onFailure(String error_msg);
}

6、重写request body 设置上传进度监听类

package com.showly.okhttpdemo.http.body;

import com.showly.okhttpdemo.http.response.IResponseHandler;
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;

/**
 * 重写request body 设置上传进度监听
 */
public class ProgressRequestBody extends RequestBody {

    private IResponseHandler mResponseHandler;      //回调监听
    private RequestBody mRequestBody;
    private BufferedSink mBufferedSink;

    public ProgressRequestBody(RequestBody requestBody, IResponseHandler responseHandler) {
        this.mResponseHandler = responseHandler;
        this.mRequestBody = requestBody;
    }

    @Override
    public MediaType contentType() {
        return mRequestBody.contentType();
    }

    @Override
    public long contentLength() throws IOException {
        return mRequestBody.contentLength();
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        if(mBufferedSink == null) {
            mBufferedSink = Okio.buffer(sink(sink));
        }

        //写入
        mRequestBody.writeTo(mBufferedSink);
        //必须调用flush,否则最后一部分数据可能不会被写入
        mBufferedSink.flush();
    }

    /**
     * 写入,回调进度接口
     * @param sink Sink
     * @return Sink
     */
    private Sink sink(Sink sink) {
        return new ForwardingSink(sink) {
            //当前写入字节数
            long bytesWritten = 0L;
            //总字节长度,避免多次调用contentLength()方法
            long contentLength = 0L;

            @Override
            public void write(Buffer source, long byteCount) throws IOException {
                super.write(source, byteCount);
                if (contentLength == 0) {
                    //获得contentLength的值,后续不再调用
                    contentLength = contentLength();
                }
                //增加当前写入的字节数
                bytesWritten += byteCount;
                //回调
                mResponseHandler.onProgress(bytesWritten, contentLength);
            }
        };
    }
}

7、重写responsebody 设置下载进度监听类

package com.showly.okhttpdemo.http.body;

import com.showly.okhttpdemo.http.response.DownloadResponseHandler;
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;

/**
 * 重写responsebody 设置下载进度监听
 */
public class ResponseProgressBody extends ResponseBody {

    private ResponseBody mResponseBody;
    private DownloadResponseHandler mDownloadResponseHandler;
    private BufferedSource bufferedSource;

    public ResponseProgressBody(ResponseBody responseBody, DownloadResponseHandler downloadResponseHandler) {
        this.mResponseBody = responseBody;
        this.mDownloadResponseHandler = downloadResponseHandler;
    }

    @Override
    public MediaType contentType() {
        return mResponseBody.contentType();
    }

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

    @Override
    public BufferedSource source() {
        if (bufferedSource == null) {
            bufferedSource = Okio.buffer(source(mResponseBody.source()));
        }
        return bufferedSource;
    }

    private Source source(Source source) {

        return new ForwardingSource(source) {

            long totalBytesRead;

            @Override
            public long read(Buffer sink, long byteCount) throws IOException {
                long bytesRead = super.read(sink, byteCount);
                totalBytesRead += ((bytesRead != -1) ? bytesRead : 0);
                if (mDownloadResponseHandler != null) {
                    mDownloadResponseHandler.onProgress(totalBytesRead, mResponseBody.contentLength());
                }
                return bytesRead;
            }
        };
    }
}

三、OkHttp工具类的使用
这里演示POST、GET请求方式,以Gson解析数据类型

注:使用不同的解析方式的时候,根据需求选用不同的回调接口:GsonResponseHandler(Gson解析,返回对象数据),RawResponseHandler(返回字符串数据)、JsonResponseHandler(返回JSONObject数据)、DownloadResponseHandler(返回File数据类型)

1.Post请求(使用Gson解析数据)

        Map<String, String> params = new HashMap<>();
        params.put("phone", "13512345678");

        OkHttpUtils.get().post(MainActivity.this, http://192.168.1.102:8066/loginapi/shortmsg/getShortMsg.do, params, new GsonResponseHandler<MobileCaptcha>() {
            @Override
            public void onSuccess(int statusCode, MobileCaptcha response) {
                Log.i("MainActivity=22=", statusCode + "----" + response.getStatus() + "---" + response.getMsg());
            }

            @Override
            public void onFailure(int statusCode, String error_msg) {
                Log.i("MainActivity=22=", statusCode + "---" + error_msg);
            }
        });

2.Get请求(使用Gson解析数据)

Map<String, String> map = new HashMap<>();
        map.put("phone", "13512345678");

        OkHttpUtils.get().get(MainActivity.this, http://192.168.1.102:8066/loginapi/shortmsg/getShortMsg.do, map, new GsonResponseHandler<MobileCaptcha>() {
            @Override
            public void onSuccess(int statusCode, MobileCaptcha response) {
                Log.i("MainActivity=11=", statusCode + "----" + response.getStatus() + "---" + response.getMsg());
            }

            @Override
            public void onFailure(int statusCode, String error_msg) {
                Log.i("MainActivity=11=", statusCode + "---" + error_msg);
            }
        });

四、这里没有说太多关于OKhttp的理论的东西,相信理论性的东西都看的很多了,直接上代码直观明了,演示Demo代码

以下是个人公众号(longxuanzhigu),之后发布的文章会同步到该公众号,方便交流学习Android知识及分享个人爱好文章:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/longxuanzhigu/article/details/82706762