Okhttp3的封装

关于介绍的可以先看这篇文章,OkHttp3使用介绍

本次封装要实现的功能有:
1.缓存添加,删除
2.请求参数封装
3.请求头封装
4.响应结果封装
5.回调线程处理
6.请求方式设置
7.响应结果类型设置
8.支持使用自签名证书
9.下载进度监听
10.上传进度监听

使用方式介绍

在Application中进行全局初始化

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //初始化HttpManager
        new HttpManager.Builder(this).build();
    }
}

异步get请求

private void demo22() {
    String url = "http://192.168.30.217/shopping/test/demo1";
    HttpManager.getInstance().getJson(url, new HttpManager.ResultCallback() {
        @Override
        public void onFailure(Exception e) {
            System.out.println("onFailure:" + e.getMessage());
        }
        @Override
        public void onSuccess(Object o, HttpManager.Result result) throws Exception {
            System.out.println(result.getJson());
        }
    });
}

异步post请求

private void demo12() {
    Map<String, String> headerMap = new HashMap<>();
    headerMap.put("Cookie", "session=123123");

    Map<String, String> bodyMap = new HashMap();
    bodyMap.put("username", "胜哥");
    bodyMap.put("age", "20");
    bodyMap.put("hobby", "吃,喝,玩");

    String url = "http://192.168.30.217/shopping/test/demo1";
    HttpManager.getInstance().postJson(url, headerMap, bodyMap,
            new HttpManager.ResultCallback(this) {

                @Override
                public void onFailure(Exception e) {
                    System.out.println("onFailure:" + e.getMessage());
                }

                @Override
                public Object doInBackground(HttpManager.Result result) throws Exception {
                    return result.getJson().optJSONObject("user");
                }

                @Override
                public void onSuccess(Object o, HttpManager.Result result) throws Exception {
                    System.out.println("o=" + o + " result:" + result.getJson());
                }
            });
}

异步上传文件

支持批量上传

private void demo13() {
    Map<String, String> headerMap = new HashMap<>();
    headerMap.put("Cookie", "session=123123");

    Map<String, String> bodyMap = new HashMap();
    bodyMap.put("username", "胜哥");
    bodyMap.put("age", "20");
    bodyMap.put("hobby", "吃,喝,玩");

    File f1 = createFile("c.mp4");
    File f2 = createFile("timg.gif");
    List<File> file = new ArrayList<>();
    file.add(f1);
    file.add(f2);
    String url = "http://192.168.30.217/shopping/test/demo1";
    HttpManager.getInstance().postFile(url, "mulitupload", file,
            headerMap, bodyMap, HttpManager.ResponseType.JSON,
            new HttpManager.Progress() {
                @Override
                public void onProgress(long currByte, long totalByte, int progress) {
                	//上传进度监听
                    System.out.println("currByte:" + currByte + " totalByte:" + totalByte +
                            " progress:" + progress);
                }
            }, new HttpManager.ResultCallback() {
                @Override
                public void onFailure(Exception e) {
                    System.out.println("onFailure:" + e.getMessage());
                }

                @Override
                public void onSuccess(Object o, HttpManager.Result result) throws Exception {
                    System.out.println(result.getJson());
                }
            });
}

异步文件下载

private void demo21() {
    String url = "http://192.168.30.217/shopping/test/download?fileName=c.mp4";
    HttpManager.getInstance().download(url, null, null,
            new HttpManager.Progress() {
                @Override
                public void onProgress(long currByte, long totalByte, int progress) {
                    System.out.println("currByte:" + currByte + " totalByte:" + totalByte 
                    + " progress:" + progress);
                    
                    if (progress == 100) {
                        System.out.println("下载完成!!");
                    }
                }
            }, new HttpManager.ResultCallback() {
                @Override
                public void onFailure(Exception e) {
                    System.out.println("onFailure:" + e.getMessage());
                }

                @Override
                public void onSuccess(Object o, HttpManager.Result result) throws Exception {
                     copyFile(filename, result.getInputStream());
             }
            });
}


/**
* 保存下载的文件
*
* @param filename
* @param inputStream
* @throws IOException
*/
private void copyFile(String filename, InputStream inputStream) throws IOException {
   File saveDir;
   if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
       saveDir = new File(getExternalCacheDir(), "download");
   } else {
       saveDir = new File(getCacheDir(), "download");
   }
   if (!saveDir.exists()) {
       saveDir.mkdirs();
   }
   String suffix = filename.substring(filename.lastIndexOf("."));
   File saveFile = new File(saveDir, System.currentTimeMillis() + suffix);
   BufferedInputStream bis = new BufferedInputStream(inputStream);
   BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(saveFile));
   int b;
   while ((b = bis.read()) != -1) {
       bos.write(b);
   }
   bos.flush();
   bos.close();
   bis.close();
}

同步get请求

private void demo23() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            String url = "http://192.168.30.217/shopping/test/demo1";
            HttpManager.Result result = HttpManager.getInstance().getJson(url);
            System.out.println("返回结果" + result.getJson());
        }
    }).start();
}

同步post请求

private void demo24() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            String url = "http://192.168.30.217/shopping/test/demo1";
            Map<String, String> headerMap = new HashMap<>();
            headerMap.put("Cookie", "session=123123");

            Map<String, String> bodyMap = new HashMap();
            bodyMap.put("username", "胜哥");
            bodyMap.put("age", "20");
            bodyMap.put("hobby", "吃,喝,玩");
            HttpManager.Result result = HttpManager.getInstance().postJson(url,headerMap,bodyMap);
            System.out.println("返回结果" + result.getJson());
        }
    }).start();
}

同步下载的文件

private void demo25() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            String filename = "c.mp4";
            String url = "http://192.168.30.217/shopping/test/download?fileName=" + filename;
            HttpManager.Result result = HttpManager.getInstance().download(url,
                    null, null,
                    new HttpManager.Progress() {
                        @Override
                        public void onProgress(long currByte, long totalByte, int progress) {
                            System.out.println("currByte:" + currByte + " totalByte:" + totalByte +
                                    " progress:" + progress);
                            if (progress == 100) {
                                System.out.println("下载完成!!");
                            }
                        }
                    });
            try {
                copyFile(filename, result.getInputStream());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

同步上传文件

private void demo26() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Map<String, String> headerMap = new HashMap<>();
            headerMap.put("Cookie", "session=123123");

            Map<String, String> bodyMap = new HashMap();
            bodyMap.put("username", "胜哥");
            bodyMap.put("age", "20");
            bodyMap.put("hobby", "吃,喝,玩");

            File f1 = createFile("c.mp4");
            File f2 = createFile("timg.gif");
            List<File> file = new ArrayList<>();
            file.add(f1);
            file.add(f2);
            String url = "http://192.168.30.217/shopping/test/demo1";

            HttpManager.Result result = HttpManager.getInstance().postFile(url, "mulitupload",
                    file, headerMap, bodyMap, HttpManager.ResponseType.JSON,
                    new HttpManager.Progress() {
                        @Override
                        public void onProgress(long currByte, long totalByte, int progress) {
                            System.out.println("currByte:" + currByte + " totalByte:" + totalByte +
                                    " progress:" + progress);
                            if (progress == 100) {
                                System.out.println("上传完成!!");
                            }
                        }
                    });
            System.out.println("返回结果" + result.getJson());
        }
    }).start();
}

库的封装

下面介绍okhttp3的封装过程

从HttpManager的初始化入手,这里我使用Builder的方式来初始化,Builder是一个内部类

/**
* Builder类,用于初始化HttpManager
*/
public static class Builder {
   private File cacheDir; //缓存路径
   private long cacheSize = CACHE_SIZE;//缓存大小
   private long readTimeout = 20;//读取的超时时间
   private long writeTimeout = 20;//写入的超时时间
   private long connectTimeout = 15;//连接的超时时间
   private Application context; //上下文
   private SSLSocketFactory sslSocketFactory;//https连接验证工厂

   public Builder(Application application) {
       this.context = application;
   }

   public Builder setCacheSize(long cacheSize) {
       this.cacheSize = cacheSize;
       return this;
   }

   public Builder setCacheDir(File cacheDir) {
       this.cacheDir = cacheDir;
       return this;
   }

   public Builder setReadTimeout(long readTimeout) {
       this.readTimeout = readTimeout;
       return this;
   }

   public Builder setWriteTimeout(long writeTimeout) {
       this.writeTimeout = writeTimeout;
       return this;
   }

   public Builder setConnectTimeout(long connectTimeout) {
       this.connectTimeout = connectTimeout;
       return this;
   }

   //设置受信任的证书
   public Builder setCertificates(InputStream... certificates) {
       try {
           CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
           KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
           keyStore.load(null);
           int index = 0;
           for (InputStream certificate : certificates) {
               String certificateAlias = Integer.toString(index++);
               keyStore.setCertificateEntry(certificateAlias,
                       certificateFactory.generateCertificate(certificate));

               try {
                   if (certificate != null)
                       certificate.close();
               } catch (IOException e) {
               }
           }

           SSLContext sslContext = SSLContext.getInstance("TLS");

           TrustManagerFactory trustManagerFactory =
                   TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

           trustManagerFactory.init(keyStore);
           sslContext.init(
                   null,
                   trustManagerFactory.getTrustManagers(),
                   new SecureRandom()
           );
           this.sslSocketFactory = sslContext.getSocketFactory();
       } catch (Exception e) {
           e.printStackTrace();
       }

       return this;
   }

   public HttpManager build() {
       if (this.cacheDir == null) {
           this.cacheDir = createCacheDir(this.context);
       }
       return mInstance = new HttpManager(cacheDir, cacheSize, connectTimeout,
               readTimeout, writeTimeout, sslSocketFactory);
   }

	
}

接着是在HttpManager的构造方法中对OkHttpClient进行全局初始化

public class HttpManager {
  	private static volatile HttpManager mInstance;
    private static final long CACHE_SIZE = 10 * 1024 * 1024;//缓存区大小
    private static Cache cache;
    private OkHttpClient mClient;

    /**
     * 构造方法初始化OkHttpClient
     *
     * @param cacheDir
     * @param cacheSize
     * @param connectTimeout
     * @param readTimeout
     * @param writeTimeout
     * @param sslSocketFactory
     */
    private HttpManager( File cacheDir, long cacheSize, long connectTimeout, long readTimeout,
                        long writeTimeout, SSLSocketFactory sslSocketFactory) {
        //初始化OkHttpClient.Builder
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .cache(cache = new Cache(cacheDir, cacheSize))
                .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                .readTimeout(readTimeout, TimeUnit.SECONDS)
                .writeTimeout(writeTimeout, TimeUnit.SECONDS);

        X509TrustManager x509TrustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
                //校验客户端证书,不做处理就是接受任意客户端证书
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
                //校验服务器端证书,不做处理就是接受任意服务端证书
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
        if (null != sslSocketFactory) {
            //使用自签名证书验证
            //如果访问的不是自签名的网站就会报这个异常:
            // java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            builder.sslSocketFactory(sslSocketFactory, x509TrustManager)
                    .hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        } else {
            //信任所有证书
            builder.sslSocketFactory(getDefaultSslSocketFactory(x509TrustManager), x509TrustManager)
                    .hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        }
        mClient = builder.build();
    }

    public SSLSocketFactory getDefaultSslSocketFactory(X509TrustManager x509TrustManager) {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager}, null);
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

接着是提供HttpManager获取实例的方法

/**
 * 获取实例
 *
 * @return
 */
public static HttpManager getInstance() {
	//获取实例时,如果缓存被清空了,需要重新初始化
    if (cache != null && cache.isClosed()) {
        try {
            //重新初始化cache
            cache.initialize();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return mInstance;
}

操作缓存的方法

/**
 * 创建缓存目录
 *
 * @param context
 * @return
 */
private static File createCacheDir(Context context) {
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        return new File(context.getExternalCacheDir(), "okCache");
    } else {
        return new File(context.getCacheDir(), "okCache");
    }
}

/**
 * 清空缓存
 *
 * @param context
 */
public static void deleteCache(Context context) {
    if (cache != null) {
        try {
            cache.delete();
            cache = new Cache(createCacheDir(context), CACHE_SIZE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * 根据url获取缓存文件
 *
 * @param url
 * @return
 */
public static File getCache(String url) {
    if (url == null) throw new NullPointerException("url == null");
    return new File(cache.directory(), okhttp3.Cache.key(HttpUrl.parse(url)) + ".1");
}

请求方式、请求类型、响应类型都是通过枚举方式事先定义好

//请求方式
public enum RequestMethod {
    GET, POST
}

//请求类型,强制网络,强制缓存,网络优先
public enum RequestType {
    FORCE_NETWORK, FORCE_CACHE, NETWORK_FIRST
}

//响应类型,json,字符串,流,字节数组
public enum ResponseType {
    JSON, STRING, IO, BYTES
}

响应结果的封装

/**
 * 结果封装
 */
public static class Result {
    private String content;//结果类型是字符串时返回
    private Map<String, List<String>> headers;//响应头
    private int code;//响应状态码
    private InputStream inputStream;//结果类型是流时返回
    private byte[] bytes;//结果类型是字节数组时返回
    private int resultType;//结果来自网络还是缓存
    private String url;//请求的url
    private JSONObject json;//结果类型是json时返回

    public static final int TYPE_NETWORK = 0;//来自网络
    public static final int TYPE_CACHE = 1;//来自缓存

    public Result(ResponseType responseType, Response response) throws Exception {
        if (null != response) {
          	this.url = response.request().url().toString();
            this.code = response.code();
            this.headers = response.headers().toMultimap();
            this.resultType = response.networkResponse() != null ? TYPE_NETWORK : TYPE_CACHE;
			
			if (null != response.body()) {
	            switch (responseType) {
	                 case JSON:
	                     this.json = new JSONObject(response.body().string());
	                     break;
	                 case STRING:
	                     this.content = response.body().string();
	                     break;
	                 case IO:
	                     this.inputStream = response.body().byteStream();
	                     break;
	                 case BYTES:
	                     this.bytes = response.body().bytes();
	                     break;
	                 default:
	                     this.content = response.body().string();
	                     break;
	             }
         	}
        }
        
    }

    public String getContent() {
        return content;
    }

    public Map<String, List<String>> getHeaders() {
        return headers;
    }

    public int getCode() {
        return code;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public byte[] getBytes() {
        return bytes;
    }

    public int getResultType() {
        return resultType;
    }

    public String getUrl() {
        return url;
    }

    public JSONObject getJson() {
        return json;
    }

}

响应结果的回调在UI线程的内部类

/**
* 结果处理,让结果回调在主线程
*/
public abstract static class ResultCallback {
   final int MSG_SUCCESS = 0;//成功
   final int MSG_FAILURE = -1;//失败
   WeakReference<Context> context;//发起请求时的上下文,可选,处理请求的页面结束后,不回调结果

   //在UI线程中处理回调
   Handler mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
       @Override
       public boolean handleMessage(Message msg) {
           if (msg.what == MSG_FAILURE) {
               onFailure((Exception) msg.obj);
           } else if (msg.what == MSG_SUCCESS) {
               Object[] obj = (Object[]) msg.obj;
               try {
                   onSuccess(obj[0], (Result) obj[1]);
               } catch (Exception e) {
                   onFailure(e);
               }
           }
           return true;
       }
   });

   public ResultCallback() {

   }

   public ResultCallback(Context ctx) {
       this.context = new WeakReference<Context>(ctx);
   }

   public final void onError(Exception e) {
       if (!checkContext()) {
           mHandler.removeCallbacksAndMessages(null);
           return;
       }
       mHandler.sendMessage(mHandler.obtainMessage(MSG_FAILURE, e));
   }


   public final void onResponse(ResponseType responseType, Response response) throws IOException {
       if (!checkContext()) {
           mHandler.removeCallbacksAndMessages(null);
           return;
       }
       try {
           //子线程中运行,封装结果
           Result result = new Result(responseType, response);
           Object o = doInBackground(result);//回调子线程方法,有需要的可以重写该方法
           mHandler.sendMessage(mHandler.obtainMessage(MSG_SUCCESS, new Object[]{o, result}));
       } catch (Exception e) {
           mHandler.sendMessage(mHandler.obtainMessage(MSG_FAILURE, e));
       }

   }

   /**
    * 如果有传context,那么判断context是否有效,如果无效则不需要回调结果了
    *
    * @return
    */
   private boolean checkContext() {
       if (null != this.context && null != context.get()) {
           Context ctx = context.get();
           while (ctx instanceof ContextWrapper) {
               ctx = ((ContextWrapper) ctx).getBaseContext();
               if (ctx instanceof Activity) {
                   Activity activity = (Activity) ctx;
                   if (activity.isFinishing() || activity.isDestroyed()) {
                       return false;
                   }
               }
           }
           if (ctx == null) {
               return false;
           }
       }
       return true;
   }

   //处理在子线程中
   public Object doInBackground(Result result) throws Exception {
       return null;
   }

   //处理在UI线程中,失败回调
   public abstract void onFailure(Exception e);

   //处理在UI线程中,成功回调
   public abstract void onSuccess(Object o, Result result) throws Exception;

}

添加请求或者响应进度的回调内部类

/**
* 响应/请求 监听 
*/
public abstract static class Progress {


   public long startIndex() {
       //初始响应的位置
       return 0;
   }

   public boolean returnOnMainThread() {
       //在主线程中返回
       return true;
   }


   /**
    * 持续进度显示
    *
    * @param currByte  当前读/写字节数
    * @param totalByte 总字节数
    * @param progress  响应进度0~100
    */
   public abstract void onProgress(long currByte, long totalByte, int progress);
}

处理UI线程回调进度的Handler内部类

private static class UIHandler extends Handler {
    Progress mProgress;

    public UIHandler(Progress progress) {
        super(Looper.getMainLooper());
        this.mProgress = progress;
    }

    @Override
    public void handleMessage(Message msg) {
        if (msg.what == 200 && null != mProgress) {
            long[] obj = (long[]) msg.obj;
            mProgress.onProgress(obj[0], obj[1], (int) obj[2]);
        }
    }
}

处理响应进度的内部类,通过装饰者模式对ResponseBody进行增强,用于处理文件的下载进度获取

private class ProgressResponseBody extends ResponseBody {
    private Progress mProgress;
    private ResponseBody mResponseBody;
    private Handler mHandler;

    public ProgressResponseBody(ResponseBody responseBody, Progress progress) {
        this.mProgress = progress;
        this.mResponseBody = responseBody;
        this.mHandler = new UIHandler(mProgress);
    }

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

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

    @Override
    public BufferedSource source() {
        return Okio.buffer(new ForwardingSource(mResponseBody.source()) {
            //总读取字节数
            long totalBytesRead = 0L;

            @Override
            public long read(Buffer sink, long byteCount) throws IOException {
                //当前已读字节数,若已读完则返回-1
                long bytesRead = super.read(sink, byteCount);
                if (mProgress != null) {
                    totalBytesRead += bytesRead == -1 ? 0 : bytesRead;
                    long curr = totalBytesRead + mProgress.startIndex();//如果有开始位置,则加上开始位置
                    int progress = (int) (curr * 100 / contentLength());

                    if (mProgress.returnOnMainThread()) {
                        //将结果发送到UI线程中
                        long[] obj = new long[]{curr, contentLength(), progress};
                        mHandler.sendMessage(mHandler.obtainMessage(200, obj));
                    } else {
                        //结果保持在子线程中回调
                        mProgress.onProgress(curr, contentLength(), progress);
                    }


                }
                return bytesRead;
            }
        });
    }
}

处理请求进度的内部类,通过装饰者模式对RequestBody进行增强,用于处理文件的上传进度获取

private class ProgressRequestBody extends RequestBody {

    private RequestBody mRequestBody;
    private long totalByte;
    private Handler mHandler;
    private Progress mProgress;

    public ProgressRequestBody(RequestBody requestBody, Progress progress) {
        this.mRequestBody = requestBody;
        this.mProgress = progress;
        this.mHandler = new UIHandler(mProgress);
        if (mRequestBody instanceof MultipartBody) {
            MultipartBody multipartBody = (MultipartBody) mRequestBody;
            for (MultipartBody.Part part : multipartBody.parts()) {
                if (null != part.body().contentType()) { //普通参数设置是没有contentType的
                    try {
                        totalByte += part.body().contentLength();//累计总提交的文件大小
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


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

    //包装完成的BufferedSink
    private BufferedSink bufferedSink;

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        if (bufferedSink == null) {
            //包装
            bufferedSink = Okio.buffer(new ForwardingSink(sink) {
                //当前写入字节数
                long bytesWritten = 0L;

                @Override
                public void write(Buffer source, long byteCount) throws IOException {
                    super.write(source, byteCount);
                    if (null != mProgress) {
                        //增加当前写入的字节数
                        bytesWritten += byteCount;
                        /**
                         * 回调,最终bytesWritten肯定是大于totalByte的,查看源码可知输出的内容还包括其他的
                         * 例如请求头数据,请求参数等等
                         */
                        if (bytesWritten > totalByte) {
                            bytesWritten = totalByte;
                        }
                        int progress = (int) (bytesWritten * 100 / totalByte);
                        if (mProgress.returnOnMainThread()) {
                            //将结果发送到UI线程中
                            long[] obj = new long[]{bytesWritten, totalByte, progress};
                            mHandler.sendMessage(mHandler.obtainMessage(200, obj));
                        } else {
                            //结果保持在子线程中回调
                            mProgress.onProgress(bytesWritten, totalByte, progress);
                        }
                    }

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

下面是HttpManager 异步请求的总入口方法

/**
 * GET/POST异步请求
 *
 * @param url          请求url
 * @param file         上传的文件
 * @param fileName     上传文件表单的name属性名称
 * @param headerMap    请求头
 * @param bodyMap      请求参数
 * @param method       请求方式
 * @param requestType  请求类型
 * @param responseType 响应数据类型
 * @param progress     响应进度,用于下载文件时的进度监听
 * @param callback     回调结果
 */
public void asyncRequest(String url, String fileName, List<File> file,
                         Map<String, String> headerMap, Map<String, String> bodyMap,
                         RequestMethod method, RequestType requestType,
                         ResponseType responseType, Progress progress, ResultCallback callback) {
    if (mClient == null) {
        throw new RuntimeException("HttpManager must be initialized");
    }
    if (null != file) {
        //上传文件请求
        doRequest(initRequest(url, fileName, file, headerMap, bodyMap,
                RequestMethod.POST, progress), RequestType.FORCE_NETWORK, responseType,
                null, true, callback);
    } else {
        //其他请求
        doRequest(initRequest(url, null, null, headerMap,
                bodyMap, method, null), requestType, responseType, progress, true, callback);
    }

}

同步请求总入口方法

/**
 * GET/POST同步请求
 *
 * @param url
 * @param fileName
 * @param file
 * @param headerMap
 * @param bodyMap
 * @param method
 * @param requestType
 * @param responseType
 * @param progress
 * @return Result
 */
public Result syncRequest(String url, String fileName, List<File> file,
                          Map<String, String> headerMap, Map<String, String> bodyMap,
                          RequestMethod method, RequestType requestType,
                          ResponseType responseType, Progress progress) {
    if (mClient == null) {
        throw new RuntimeException("HttpManager must be initialized");
    }
    if (null != file) {
        //上传文件请求
        return doRequest(initRequest(url, fileName, file, headerMap, bodyMap,
                RequestMethod.POST, progress), RequestType.FORCE_NETWORK, responseType,
                null, false, null);
    } else {
        //其他请求
        return doRequest(initRequest(url, null, null, headerMap,
                bodyMap, method, null), requestType, responseType, progress,
                false, null);
    }
}

initRequest 方法初始化请求

//初始化请求
private Request.Builder initRequest(String url, String fileName, List<File> file,
                                    Map<String, String> headerMap, Map<String, String> bodyMap,
                                    RequestMethod method, Progress progress) {
    //构建请求
    Request.Builder requestBuilder = new Request.Builder();
    if (method == RequestMethod.GET) {
        url = attachGetParams(url, bodyMap);//get请求参数拼接
        requestBuilder.get();
    } else {
        //添加post请求参数封装
        if (null != file && file.size() > 0) {
            if (TextUtils.isEmpty(fileName)) {
                throw new IllegalArgumentException("文件上传表单的name不能为空");
            }
            //文件上传表单数据封装
            MultipartBody.Builder form = new MultipartBody.Builder();
            form.setType(MultipartBody.FORM);//支持文件上传的表单格式
            //循环封装File参数
            for (File f : file) {
                MediaType mediaType = MediaType.parse("text/x-markdown;charset=utf-8");
                RequestBody fileBody = RequestBody.create(mediaType, f);
                form.addFormDataPart(fileName, f.getName(), fileBody);//上传文件
            }
            //上传普通参数
            if (null != bodyMap) {
                for (String key : bodyMap.keySet()) {
                    form.addFormDataPart(key, bodyMap.get(key));
                }
            }
            requestBuilder.post(new ProgressRequestBody(form.build(), progress));
        } else {
            //普通表单数据封装
            if (null != bodyMap) {
                FormBody.Builder form = new FormBody.Builder();
                for (String key : bodyMap.keySet()) {
                    form.add(key, bodyMap.get(key));
                }
                requestBuilder.post(form.build());
            }
        }


    }
    //请求url和tag设置
    requestBuilder.url(url).tag(url);
    //请求头设置
    if (null != headerMap) {
        for (String key : headerMap.keySet()) {
            requestBuilder.header(key, headerMap.get(key));
        }
    }

    return requestBuilder;
}

doRequest发起请求

/**
 * 发起请求
 * @param requestBuilder
 * @param requestType
 * @param responseType
 * @param progress
 * @param async true 异步,false 同步
 * @param callback 异步结果回调
 * @return Result 同步结果返回
 */
private Result doRequest(final Request.Builder requestBuilder, final RequestType requestType,
                         final ResponseType responseType, final Progress progress,
                         boolean async, final ResultCallback callback) {
    //设置缓存类型
    switch (requestType) {
        case FORCE_CACHE:
            requestBuilder.cacheControl(CacheControl.FORCE_CACHE);
            break;
        case FORCE_NETWORK:
        case NETWORK_FIRST:
        default:
            requestBuilder.cacheControl(CacheControl.FORCE_NETWORK);
            break;
    }

    //监听响应进度,一般用于文件下载进度监听
    final OkHttpClient client = mClient.newBuilder()
            .addNetworkInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    //获取原始Response
                    Response originalResponse = chain.proceed(chain.request());
                    //返回新的Response
                    return originalResponse.newBuilder()
                            .body(new ProgressResponseBody(originalResponse.body(), progress))
                            .build();
                }
            })
            .build();

    //异步请求回调
    Callback asynCallback = new Callback() {
        int count;//请求失败的回调次数

        @Override
        public void onFailure(Call call, IOException e) {
            if (count == 0) {
                //网络优先失败,则请求缓存
                if (requestType == RequestType.NETWORK_FIRST) {
                    count++;
                    Request request = requestBuilder.cacheControl(CacheControl.FORCE_CACHE).build();
                    client.newCall(request).enqueue(this);
                } else {
                    if (null != callback)
                        callback.onError(e);
                }
            } else {
                //第二次请求缓存也失败,这直接回调
                if (null != callback)
                    callback.onError(e);
            }

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (null != response && response.isSuccessful() && response.body() != null) {
                if (null != callback)
                    callback.onResponse(responseType, response);
            } else {
                if (null != callback)
                    callback.onError(new Exception("Response is null"));
            }
        }
    };
    if (async) {
        client.newCall(requestBuilder.build()).enqueue(asynCallback);
    } else {
        //同步请求
        try {
            Response response = client.newCall(requestBuilder.build()).execute();
            if (null == response || !response.isSuccessful() || response.body() == null) {
                if (requestType == RequestType.NETWORK_FIRST) {
                    //网络优先失败,则请求缓存
                    Request request = requestBuilder.cacheControl(CacheControl.FORCE_CACHE).build();
                    response = client.newCall(request).execute();
                }
            }
            return new Result(responseType, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return null;
}

下面是几个重载的请求方法

/**
 * 异步get请求,获取json数据
 * @param url
 * @param callback
 */
public void getJson(String url, ResultCallback callback) {
    getJson(url, null, null, callback);
}

/**
 * 异步get请求,获取json数据
 *
 * @param url
 * @param headerMap
 * @param bodyMap
 * @param callback
 */
public void getJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
                    ResultCallback callback) {

    asyncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
            RequestType.NETWORK_FIRST, ResponseType.JSON, null, callback);
}


/**
 * 异步POST请求,获取json数据
 *
 * @param url
 * @param headerMap
 * @param bodyMap
 * @param callback
 */
public void postJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
                     ResultCallback callback) {
    asyncRequest(url, null, null, headerMap, bodyMap, RequestMethod.POST,
            RequestType.FORCE_NETWORK, ResponseType.JSON, null, callback);
}

/**
 * 异步下载文件
 *
 * @param url
 * @param headerMap
 * @param bodyMap
 * @param progress  下载监听
 * @param callback
 */
public void download(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
                     Progress progress, ResultCallback callback) {
    asyncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
            RequestType.FORCE_NETWORK, ResponseType.IO, progress, callback);
}

/**
 * 异步异步上传文件
 *
 * @param url          请求url
 * @param file         上传的文件
 * @param fileName     上传文件表单的name属性名称
 * @param headerMap    请求头
 * @param bodyMap      请求参数
 * @param responseType 响应类型
 * @param progress     上传进度监听
 * @param callback     回调结果
 */
public void postFile(String url, String fileName, List<File> file, Map<String, String> headerMap,
                     Map<String, String> bodyMap, ResponseType responseType, Progress progress,
                     ResultCallback callback) {

    asyncRequest(url, fileName, file, headerMap, bodyMap, null, null,
            responseType, progress, callback);
}

/**
 * 同步get请求
 * @param url
 * @return
 */
public Result getJson(String url) {
    return getJson(url, null, null);
}

/**
 * 同步get请求
 *
 * @param url
 * @param headerMap
 * @param bodyMap
 * @return Result
 */
public Result getJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap) {
    return syncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
            RequestType.NETWORK_FIRST, ResponseType.JSON, null);
}

/**
 * 同步post请求
 * @param url
 * @param headerMap
 * @param bodyMap
 * @return Result
 */
public Result postJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap) {
   return syncRequest(url, null, null, headerMap, bodyMap, RequestMethod.POST,
            RequestType.FORCE_NETWORK, ResponseType.JSON, null);
}

/**
 * 同步下载文件
 * @param url
 * @param headerMap
 * @param bodyMap
 * @param progress 下载进度监听
 * @return Result
 */
public Result download(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
                       Progress progress) {
    return syncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
            RequestType.FORCE_NETWORK, ResponseType.IO, progress);
}

/**
 * 同步提交文件
 *
 * @param url
 * @param fileName
 * @param file
 * @param headerMap
 * @param bodyMap
 * @param responseType
 * @param progress
 * @return Result
 */
public Result postFile(String url, String fileName, List<File> file, Map<String, String> headerMap,
                       Map<String, String> bodyMap, ResponseType responseType, Progress progress) {
    return syncRequest(url, fileName, file, headerMap, bodyMap, RequestMethod.POST,
            RequestType.FORCE_NETWORK, responseType, progress);
}

搞定~~

源码下载

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值