OKHttp3.10.0最新版的极致封装

我们都知道,Retrofit目前是比较火的网络请求框架,本身就是是OKHttp进行了封装,实际干活的还是OKhttp,所以为了更好的用好Retrofit,很有必要复习一下OKHTTP,并且OKhttp的最新版本3.10.0和之前版本的操作也是不尽相同,所以今天重新对他操作一波,从简单实用到常用使用方式的封装均有涉猎,亲测可以正常使用,本文以豆瓣的电影api做测试数据,详细源码下方会有下载地址,时间紧迫,废话不多说,代码就是最好的注释,欢迎fork!
PS:本文主要围绕以下四个文件做操作:
这里写图片描述

OKHTTP3.10的GET请求

private void getDouBan1() {
        //1,创建OKHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //2,创建一个Request
        Request request = new Request.Builder().url(Constant.URL).build();
        //3,创建一个call对象
        Call call = okHttpClient.newCall(request);
        //4,将请求添加到调度中
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) {
                if (response.isSuccessful()) {
                    try {
                        res = response.body().string();
                        ThreadPoolUtil.execute(new Runnable() {
                            @Override
                            public void run() {
                                Log.d(TAG, res);
                            }
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

OKHTTP3.10的POST请求

private void postDouBan() {
        //1,创建OKHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //2,创建一个Request
        RequestBody requestBody = new FormBody.Builder()
                .add("username", "ytf")
                .add("password", "123")
                .build();
        Request request = new Request.Builder().url(Constant.URL).post(requestBody).build();
        //4,将请求添加到调度中
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    try {
                        res = response.body().string();
                        ThreadPoolUtil.execute(new Runnable() {
                            @Override
                            public void run() {
//                                Looper.prepare();
//                                Toast.makeText(MainActivity.this, res, Toast.LENGTH_SHORT).show();
                                Log.d(TAG, res);
                                EventBus.getDefault().post(res);
                            }
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

RequestBody示例:
这里写图片描述

OKHTTP3.10的GET封装请求

工具类的单例:

/**
     * 懒汉式加锁单例模式
     * @return
     */
    public OkHTTPManger() {
        okHttpClient = new OkHttpClient();

    }
    public static OkHTTPManger getInstance() {
        if (instance == null) {
            synchronized (OkHTTPManger.class) {
                if (instance == null) {
                    instance = new OkHTTPManger();
                }
            }
        }
        return instance;
    }

get同步请求

 /**
     * get同步请求不需要传参数
     * 通过response.body().string()获取返回的字符串
     *
     * @param url
     * @return
     */
    public String getSyncBackString(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            String responseStr = response.body().string();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }
/**
     * get同步请求
     * 通过response.body().bytes()获取返回的二进制字节数组
     *
     * @param url
     * @return
     */
    public byte[] getSyncBackByteArray(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            byte[] responseStr = response.body().bytes();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为byte数组异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }
 /**
     * get同步请求
     * 通过response.body().byteStream()获取返回的二进制字节流
     *
     * @param url
     * @return
     */
    public InputStream getSyncBackByteStream(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            InputStream responseStr = response.body().byteStream();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }
/**
     * get同步请求
     * 通过response.body().byteStream()获取返回的二进制字节流
     *
     * @param url
     * @return
     */
    public Reader getSyncBackCharReader(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            Reader responseStr = response.body().charStream();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为Reader异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }

get异步请求

/**
     * get异步请求不传参数
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String getAsynBackStringWithoutParms(String url, final MyDataCallBack myDataCallBack) {

        final Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
//                 Logger.e("GET异步请求为String失败"+e.toString());
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("GET异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("GET异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }
/**
     * get异步请求传参数(可以传null)
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String getAsynBackStringWithParms(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
        if (params == null) {
            params = new HashMap<>();
        }
        // 请求url(baseUrl+参数)
        String doUrl = urlJoint(url, params);
        final Request request = new Request.Builder()
                .url(doUrl)
//                .header("Cookie", "自动管理更新需要携带的Cookie")
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
//                 Logger.e("GET异步请求为String失败"+e.toString());
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("GET异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("GET异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }


明文传参拼接URL

/**
     * @param url    实际URL的path
     * @param params
     * @return
     */
    private static String urlJoint(String url, Map<String, String> params) {
        StringBuilder realURL = new StringBuilder(Constant.URL);
        realURL = realURL.append(url);
        boolean isFirst = true;
        if (params == null) {
            params = new HashMap<>();
        } else {
            Set<Map.Entry<String, String>> entrySet = params.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                if (isFirst && !url.contains("?")) {
                    isFirst = false;
                    realURL.append("?");
                } else {
                    realURL.append("&");
                }
                realURL.append(entry.getKey());
                realURL.append("=");
                if (entry.getValue() == null) {
                    realURL.append(" ");
                } else {
                    realURL.append(entry.getValue());
                }

            }
        }

        return realURL.toString();
    }

##OKHTTP3.10的POST封装请求

post异步请求map传参

/**
     * post异步请求map传参
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String postAsynBackString(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
        RequestBody requestBody;
        if (params == null) {
            params = new HashMap<>();
        }

        FormBody.Builder builder = new FormBody.Builder();
        /**
         * 在这对添加的参数进行遍历
         */
        addMapParmsToFromBody(params, builder);

        requestBody = builder.build();
        String realURL = urlJoint(url, null);
        //结果返回
        final Request request = new Request.Builder()
                .url(realURL)
                .post(requestBody)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }

将参数添加到请求体

 private void addMapParmsToFromBody(Map<String, String> params, FormBody.Builder builder) {
        for (Map.Entry<String, String> map : params.entrySet()) {
            String key = map.getKey();
            String value;
            /**
             * 判断值是否是空的
             */
            if (map.getValue() == null) {
                value = "";
            } else {
                value = map.getValue();
            }
            /**
             * 把key和value添加到formbody中
             */
            builder.add(key, value);
        }
    }

post异步请求json传参

/**
     * post异步请求json传参
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String postAsynRequireJson(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {

        if (params == null) {
            params = new HashMap<>();
        }
        // 将map转换成json,需要引入Gson包
        String mapToJson = new Gson().toJson(params);
        final String realURL = urlJoint(url, null);
        final Request request = buildJsonPostRequest(realURL, mapToJson);
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }

效果图:
这里写图片描述

以json方式传入请求体

**
     * Json_POST请求参数
     *
     * @param url  url
     * @param json json
     * @return requestBody
     */
    private Request buildJsonPostRequest(String url, String json) {
//        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        RequestBody requestBody = RequestBody.create(JSON, json);
        return new Request.Builder().url(url).post(requestBody).build();
    }

以String方式传入请求体

/**
     * String_POST请求参数
     *
     * @param url  url
     * @param json json
     * @return requestBody
     */
    private Request buildStringPostRequest(String url, String json) {
        RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, json);
        return new Request.Builder().url(url).post(requestBody).build();
    }

文件上传:

基于http的文件上传(传入文件名和key)

 /**
     * 基于http的文件上传(传入文件名和key)
     * 通过addFormDataPart
     *
     * @param url            URL的Path部分
     * @param myDataCallBack 自定义回调接口
     *                       将file作为请求体传入到服务端.
     * @param fileKey        文件传入服务器的键"image"
     * @fileName: "pic.png"
     */
    private void upLoadMultiFileSimple(String url, String fileName, String fileKey, final MyDataCallBack myDataCallBack) {
        File file = new File(Environment.getExternalStorageDirectory(), fileName);
        RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(fileKey, fileName, fileBody)
                .build();
        final String realURL = urlJoint(url, null);
        final Request request = new Request.Builder()
                .url(realURL)
                .post(requestBody)
                .build();

        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步文件上传失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步文件上传异常" + e.toString());
            e.printStackTrace();
        }
    }

基于http的文件上传,混合参数和文件请求

 /**
     * 基于http的文件上传(传入文件数组和key)混合参数和文件请求
     * 通过addFormDataPart可以添加多个上传的文件
     *
     * @param url            URL的Path部分
     * @param myDataCallBack 自定义回调接口
     *                       将file作为请求体传入到服务端.
     * @param files          上传的文件
     * @param fileKeys       上传的文件key集合
     */
    private void upLoadMultiFile(String url, File[] files, String[] fileKeys, Map<String, String> params, final MyDataCallBack myDataCallBack) {
        if (params == null) {
            params = new HashMap<>();
        }
        final String realURL = urlJoint(url, null);
        FormBody.Builder builder = new FormBody.Builder();
        addMapParmsToFromBody(params, builder);
        RequestBody requestBody = builder.build();
        MultipartBody.Builder multipartBody = new MultipartBody.Builder();
        multipartBody.setType(MultipartBody.ALTERNATIVE)
                .addPart(requestBody);

        if (files != null) {
            RequestBody fileBody = null;
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                String fileName = file.getName();
                fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                //TODO 根据文件名设置contentType
                multipartBody.addPart(Headers.of("Content-Disposition",
                        "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
                        fileBody);
            }

        }

        final Request request = new Request.Builder()
                .url(realURL)
                .post(multipartBody.build())
                .build();

        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(call.request(), e);
                }

                @Override
                public void onResponse(Call call, Response response)  {
                    try {
                        myDataCallBack.requestSuccess(response.body().string());

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步文件上传失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步文件上传异常" + e.toString());
            e.printStackTrace();
        }
    }
***************************************************************************************
  private String guessMimeType(String fileName) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(fileName);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;

    }

文件下载

/**
     * 文件下载
     * @param url path路径
     * @param destFileDir 本地存储的文件夹路径
     * @param myDataCallBack 自定义回调接口
     */
    private void downLoadFileAsyn(final String url, final String destFileDir, final MyDataCallBack myDataCallBack){
        String realURL=urlJoint(url,null);
        Request request=new Request.Builder()
                .url(realURL)
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                myDataCallBack.requestFailure(call.request(),e);

            }

            @Override
            public void onResponse(Call call, Response response) {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                is = response.body().byteStream();
                File file = new File(destFileDir, getFileName(url));
                try {
                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1)
                    {
                        fos.write(buf, 0, len);
                    }
                    fos.flush();
                } catch (IOException e) {
                    Logger.e("文件下载异常:",e.getMessage());
                    e.printStackTrace();
                }finally {
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                            Logger.e("文件流关闭异常:",e.getMessage());
                            e.printStackTrace();
                        }
                    }
                    if (fos != null) {
                        try {
                            fos.close();
                        } catch (IOException e) {
                            Logger.e("文件流关闭异常:",e.getMessage());
                            e.printStackTrace();
                        }
                    }

                }

                //如果下载文件成功,第一个参数为文件的绝对路径
                sendSuccessResultCallback(file.getAbsolutePath(), myDataCallBack);

                myDataCallBack.requestSuccess(response.body().toString());

            }
        });
    }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
private String getFileName(String url) {
        int separatorIndex = url.lastIndexOf("/");
        return (separatorIndex < 0) ? url : url.substring(separatorIndex + 1, url.length());

    }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
private void sendSuccessResultCallback(final String absolutePath, final MyDataCallBack myDataCallBack) {
        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                if (myDataCallBack!=null){
                    myDataCallBack.requestSuccess(absolutePath);
                }
            }
        });
    }

自定义CallBack回调MyDataCallBack

package com.app.ytf.httpdemo.okhttp;


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

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import okhttp3.Request;

/**
 * @author ytf
 * 正常情况下多数返回的是string格式,
 * 如果要接收返回其他类型的数据可以依照需求放开注释,
 * 使用参照同步请求做法
 */
public abstract class MyDataCallBack<T> {
    //请求数据的返回类型,包含常见的(Bean,List等)
    Type mType;

    public MyDataCallBack() {
//        mType=getSuperclassTypeParameter(getClass());
    }

    /**
     * 通过反射返回想要的类型
     * @param subclass
     * @return
     */

    static Type getSuperclassTypeParameter(Class<?> subclass) {
        Type superclass = subclass.getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new RuntimeException("未知返回类型");
        }
        ParameterizedType parameterized = (ParameterizedType) superclass;
        return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
    }
    /**
     * 在请求之前的方法,一般用于加载进度框ProgressBar展示
     *
     * @param request
     */
    public  abstract void onBefore(Request request);

    public abstract void requestSuccess(T result);

//    void requestSuccess(Reader result) throws Exception;
//    void requestSuccess(InputStream result) throws Exception;
//    void requestSuccess(byte[] result) throws Exception;

    public abstract void requestFailure(Request request, IOException e);

    /**
     * 在请求之后的方法,一般用于加载框隐藏
     */
    public abstract void onAfter();
}

自定义日志拦截器

package com.app.ytf.httpdemo.okhttp;

import com.orhanobut.logger.Logger;

import java.io.IOException;
import java.util.Locale;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

/**
 * @author ytf
 * 自定义拦截器
 * Chain 对象可以拿到当前请求的 Request 对象,然后我们可以对Request做二次处理,
 * 最后生成我们需要的请求,然后再通过网络发送请求到服务端,这样就完成了一次拦截
 */
public class HeaderInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();
        Logger.d(String.format("Sending request %s on %s%n%s", request.url(),  chain.connection(), request.headers()));

        long t1 = System.nanoTime();
        okhttp3.Response response = chain.proceed(chain.request());
        long t2 = System.nanoTime();
        Logger.d(String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s",
                response.request().url(), (t2 - t1) / 1e6d, response.headers()));

        okhttp3.MediaType mediaType = response.body().contentType();
        String content = response.body().string();
        Logger.json(content);
        Response response1=chain.proceed(request);
        Logger.d("返回response:",response1.toString());
        return response.newBuilder()
                .header("Authorization", "请求头授权信息拦截")
                .body(okhttp3.ResponseBody.create(mediaType, content))
                .build();


    }
}

自定义网络拦截器

package com.app.ytf.httpdemo.okhttp;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

import com.app.ytf.httpdemo.APP;

import java.io.IOException;

import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

/**
 * @author ytf
 * 设置网络拦截器,实现在线和离线缓存
 */
public class CacheInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        if (!isNetworkConnected()) {
            request = request.newBuilder()
                    .cacheControl(CacheControl.FORCE_CACHE)
                    .build();
        }
        Response originalResponse = chain.proceed(request);
        if (isNetworkConnected()) {
            //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置(注掉部分)
            String cacheControl = request.cacheControl().toString();
            return originalResponse.newBuilder()
                    .header("Cache-Control", cacheControl)
                    //.header("Cache-Control", "max-age=3600")
                    .removeHeader("Pragma") // 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
                    .build();
        } else {
//1.不需要缓存:Cache-Control: no-cache或Cache-Control: max-age=0
//2.如果想先显示数据,在请求。(类似于微博等):Cache-Control: only-if-cached
            int maxAge = 60 * 60;
            return originalResponse.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-age=" + maxAge)
                    .removeHeader("Pragma")
                    .build();
        }

    }

    /**
     * 判断网络是否可用的方法
     *
     * @return
     */
    private boolean isNetworkConnected() {
        ConnectivityManager connectivity = (ConnectivityManager) APP.getInstance()
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (null != connectivity) {
            NetworkInfo info = connectivity.getActiveNetworkInfo();
            if (null != info && info.isConnected()) {
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
        return false;
    }

}

工具类详细代码:

package com.app.ytf.httpdemo.okhttp;

import android.os.Environment;

import com.app.ytf.httpdemo.APP;
import com.app.ytf.httpdemo.util.Constant;
import com.app.ytf.httpdemo.util.ThreadPoolUtil;
import com.google.gson.Gson;
import com.google.gson.internal.$Gson$Types;
import com.orhanobut.logger.Logger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.ConnectException;
import java.net.FileNameMap;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.sql.ParameterMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * @author ytf
 */
public class OkHTTPManger {
    private static OkHttpClient okHttpClient;
    private volatile static OkHTTPManger instance;//防止多个线程同时访问
    //提交json数据
    private static final MediaType JSON = MediaType.parse("application/json;charset=utf-8");
    //提交字符串数据
    private static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown;charset=utf-8");
    private static String responseStrGETAsyn;

    private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
// 使用getCacheDir()来作为缓存文件的存放路径(/data/data/包名/cache) ,
// 如果你想看到缓存文件可以临时使用 getExternalCacheDir()(/sdcard/Android/data/包名/cache)。
    private static File cacheFile;
    private static Cache cache;

    public OkHTTPManger() {
//        if (APP.getInstance().getApplicationContext().getCacheDir()!=null){
//            cacheFile = new File(APP.getInstance().getCacheDir(), "Test");
//            cache = new Cache(cacheFile, 1024 * 1024 * 10);
//        }

        okHttpClient = new OkHttpClient();
        okHttpClient.newBuilder()
//                .addInterceptor(new HeaderInterceptor())
//                .addNetworkInterceptor(new CacheInterceptor())
//                .cache(cache)
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                        cookieStore.put(url.host(), cookies);
                    }

                    @Override
                    public List<Cookie> loadForRequest(HttpUrl url) {
                        List<Cookie> cookies = cookieStore.get(url.host());
                        return cookies != null ? cookies : new ArrayList<Cookie>();
//自动管理Cookie发送Request都不用管Cookie这个参数也不用去response获取新Cookie什么的了。还能通过cookieStore获取当前保存的Cookie。
                    }
                });
    }


    /**
     * 懒汉式加锁单例模式
     * @return
     */
    public static OkHTTPManger getInstance() {
        if (instance == null) {
            synchronized (OkHTTPManger.class) {
                if (instance == null) {
                    instance = new OkHTTPManger();
                }
            }
        }
        return instance;
    }


    /**
     * get同步请求不需要传参数
     * 通过response.body().string()获取返回的字符串
     *
     * @param url
     * @return
     */
    public String getSyncBackString(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            String responseStr = response.body().string();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get同步请求
     * 通过response.body().bytes()获取返回的二进制字节数组
     *
     * @param url
     * @return
     */
    public byte[] getSyncBackByteArray(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            byte[] responseStr = response.body().bytes();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为byte数组异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get同步请求
     * 通过response.body().byteStream()获取返回的二进制字节流
     *
     * @param url
     * @return
     */
    public InputStream getSyncBackByteStream(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            InputStream responseStr = response.body().byteStream();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get同步请求
     * 通过response.body().byteStream()获取返回的二进制字节流
     *
     * @param url
     * @return
     */
    public Reader getSyncBackCharReader(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            // 将response转化成String
            Reader responseStr = response.body().charStream();
            return responseStr;
        } catch (IOException e) {
            Logger.e("GET同步请求解析为Reader异常" + e.toString());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get异步请求不传参数
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String getAsynBackStringWithoutParms(String url, final MyDataCallBack myDataCallBack) {

        final Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
//                 Logger.e("GET异步请求为String失败"+e.toString());
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("GET异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("GET异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }

    /**
     * get异步请求传参数(可以传null)
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String getAsynBackStringWithParms(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
        if (params == null) {
            params = new HashMap<>();
        }
        // 请求url(baseUrl+参数)
        String doUrl = urlJoint(url, params);
        final Request request = new Request.Builder()
                .url(doUrl)
//                .header("Cookie", "自动管理更新需要携带的Cookie")
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
//                 Logger.e("GET异步请求为String失败"+e.toString());
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("GET异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("GET异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }

    /**
     * post异步请求map传参
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String postAsynBackString(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
        RequestBody requestBody;
        if (params == null) {
            params = new HashMap<>();
        }

        FormBody.Builder builder = new FormBody.Builder();
        /**
         * 在这对添加的参数进行遍历
         */
        addMapParmsToFromBody(params, builder);

        requestBody = builder.build();
        String realURL = urlJoint(url, null);
        //结果返回
        final Request request = new Request.Builder()
                .url(realURL)
                .post(requestBody)
                .build();
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }

    private void addMapParmsToFromBody(Map<String, String> params, FormBody.Builder builder) {
        for (Map.Entry<String, String> map : params.entrySet()) {
            String key = map.getKey();
            String value;
            /**
             * 判断值是否是空的
             */
            if (map.getValue() == null) {
                value = "";
            } else {
                value = map.getValue();
            }
            /**
             * 把key和value添加到formbody中
             */
            builder.add(key, value);
        }
    }

    /**
     * post异步请求json传参
     * 通过response.body().string()获取返回的字符串
     * 异步返回值不能更新UI,要开启新线程
     *
     * @param url
     * @return
     */
    public String postAsynRequireJson(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {

        if (params == null) {
            params = new HashMap<>();
        }
        // 将map转换成json,需要引入Gson包
        String mapToJson = new Gson().toJson(params);
        final String realURL = urlJoint(url, null);
        final Request request = buildJsonPostRequest(realURL, mapToJson);
        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步请求为String解析异常失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步请求解析为String异常" + e.toString());
            e.printStackTrace();
        }
        return responseStrGETAsyn;
    }

    /**
     * Json_POST请求参数
     *
     * @param url  url
     * @param json json
     * @return requestBody
     */
    private Request buildJsonPostRequest(String url, String json) {
//        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        RequestBody requestBody = RequestBody.create(JSON, json);
        return new Request.Builder().url(url).post(requestBody).build();
    }

    /**
     * String_POST请求参数
     *
     * @param url  url
     * @param json json
     * @return requestBody
     */
    private Request buildStringPostRequest(String url, String json) {
        RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, json);
        return new Request.Builder().url(url).post(requestBody).build();
    }

    /**
     * @param url    实际URL的path
     * @param params
     * @return
     */
    private static String urlJoint(String url, Map<String, String> params) {
        StringBuilder realURL = new StringBuilder(Constant.URL);
        realURL = realURL.append(url);
        boolean isFirst = true;
        if (params == null) {
            params = new HashMap<>();
        } else {
            Set<Map.Entry<String, String>> entrySet = params.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                if (isFirst && !url.contains("?")) {
                    isFirst = false;
                    realURL.append("?");
                } else {
                    realURL.append("&");
                }
                realURL.append(entry.getKey());
                realURL.append("=");
                if (entry.getValue() == null) {
                    realURL.append(" ");
                } else {
                    realURL.append(entry.getValue());
                }

            }
        }

        return realURL.toString();
    }

    /**
     * 基于http的文件上传(传入文件名和key)
     * 通过addFormDataPart
     *
     * @param url            URL的Path部分
     * @param myDataCallBack 自定义回调接口
     *                       将file作为请求体传入到服务端.
     * @param fileKey        文件传入服务器的键"image"
     * @fileName: "pic.png"
     */
    private void upLoadMultiFileSimple(String url, String fileName, String fileKey, final MyDataCallBack myDataCallBack) {
        File file = new File(Environment.getExternalStorageDirectory(), fileName);
        RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(fileKey, fileName, fileBody)
                .build();
        final String realURL = urlJoint(url, null);
        final Request request = new Request.Builder()
                .url(realURL)
                .post(requestBody)
                .build();

        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(request, e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        myDataCallBack.requestSuccess(responseStrGETAsyn);

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步文件上传失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步文件上传异常" + e.toString());
            e.printStackTrace();
        }
    }

    /**
     * 基于http的文件上传(传入文件数组和key)混合参数和文件请求
     * 通过addFormDataPart可以添加多个上传的文件
     *
     * @param url            URL的Path部分
     * @param myDataCallBack 自定义回调接口
     *                       将file作为请求体传入到服务端.
     * @param files          上传的文件
     * @param fileKeys       上传的文件key集合
     */
    private void upLoadMultiFile(String url, File[] files, String[] fileKeys, Map<String, String> params, final MyDataCallBack myDataCallBack) {
        if (params == null) {
            params = new HashMap<>();
        }
        final String realURL = urlJoint(url, null);
        FormBody.Builder builder = new FormBody.Builder();
        addMapParmsToFromBody(params, builder);
        RequestBody requestBody = builder.build();
        MultipartBody.Builder multipartBody = new MultipartBody.Builder();
        multipartBody.setType(MultipartBody.ALTERNATIVE)
                .addPart(requestBody);

        if (files != null) {
            RequestBody fileBody = null;
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                String fileName = file.getName();
                fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                //TODO 根据文件名设置contentType
                multipartBody.addPart(Headers.of("Content-Disposition",
                        "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
                        fileBody);
            }

        }

        final Request request = new Request.Builder()
                .url(realURL)
                .post(multipartBody.build())
                .build();

        Call call = okHttpClient.newCall(request);
        try {
            myDataCallBack.onBefore(request);
            // 请求加入调度
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    myDataCallBack.requestFailure(call.request(), e);
                }

                @Override
                public void onResponse(Call call, Response response)  {
                    try {
                        myDataCallBack.requestSuccess(response.body().string());

                    } catch (Exception e) {
                        e.printStackTrace();
                        Logger.e("POST异步文件上传失败" + e.toString());
                    }

                }
            });

            myDataCallBack.onAfter();
        } catch (Exception e) {
            Logger.e("POST异步文件上传异常" + e.toString());
            e.printStackTrace();
        }
    }

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

    }

    /**
     * 文件下载
     * @param url path路径
     * @param destFileDir 本地存储的文件夹路径
     * @param myDataCallBack 自定义回调接口
     */
    private void downLoadFileAsyn(final String url, final String destFileDir, final MyDataCallBack myDataCallBack){
        String realURL=urlJoint(url,null);
        Request request=new Request.Builder()
                .url(realURL)
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                myDataCallBack.requestFailure(call.request(),e);

            }

            @Override
            public void onResponse(Call call, Response response) {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                is = response.body().byteStream();
                File file = new File(destFileDir, getFileName(url));
                try {
                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1)
                    {
                        fos.write(buf, 0, len);
                    }
                    fos.flush();
                } catch (IOException e) {
                    Logger.e("文件下载异常:",e.getMessage());
                    e.printStackTrace();
                }finally {
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                            Logger.e("文件流关闭异常:",e.getMessage());
                            e.printStackTrace();
                        }
                    }
                    if (fos != null) {
                        try {
                            fos.close();
                        } catch (IOException e) {
                            Logger.e("文件流关闭异常:",e.getMessage());
                            e.printStackTrace();
                        }
                    }

                }

                //如果下载文件成功,第一个参数为文件的绝对路径
                sendSuccessResultCallback(file.getAbsolutePath(), myDataCallBack);

                myDataCallBack.requestSuccess(response.body().toString());

            }
        });
    }

    private String getFileName(String url) {
        int separatorIndex = url.lastIndexOf("/");
        return (separatorIndex < 0) ? url : url.substring(separatorIndex + 1, url.length());

    }

    private void sendSuccessResultCallback(final String absolutePath, final MyDataCallBack myDataCallBack) {
        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                if (myDataCallBack!=null){
                    myDataCallBack.requestSuccess(absolutePath);
                }
            }
        });
    }

}

源码下载地址:

点击下载demo

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值