Android之Okhttp的封装

最近需要用到网络请求,用到了Okhttp这个强大的库,写个小博客来做个笔记 先看一下Okhttp3和之前版本的不同之处。

1.Okhttp3和OkHttp的对比

  • OkHttpClient创建方式不同

例如:

OkHttpClient.Builder okHttpClientBuilder = client.newBuilder(); 
        /* 超时设置 */  
        okHttpClientBuilder.connectTimeout(10, TimeUnit.SECONDS) 
                            .writeTimeout(30, TimeUnit.SECONDS) 
                            .readTimeout(30, TimeUnit.SECONDS);
OkHttpClient mOkHttpClient = okHttpClientBuilder.build();

okhttp直接newOkHttpClient,而okhttp3中提供了Builder,很好的使用了创建者设计模式 有以下参数:

Dispatcher dispatcher; // 分发
Proxy proxy; // 代理
List protocols;
List connectionSpecs;
final List interceptors = new ArrayList<>(); // 拦截器 final List networkInterceptors = new ArrayList<>(); // 网络拦截器 ProxySelector proxySelector;
CookieJar cookieJar;
Cache cache; // 缓存
InternalCache internalCache;
SocketFactory socketFactory;
SSLSocketFactory sslSocketFactory;
HostnameVerifier hostnameVerifier;
CertificatePinner certificatePinner;
Authenticator proxyAuthenticator; // 代理证书
Authenticator authenticator; // 证书
ConnectionPool connectionPool;
Dns dns; // DNS
boolean followSslRedirects;
boolean followRedirects;
boolean retryOnConnectionFailure;
int connectTimeout;
int readTimeout;
int writeTimeout;
  • cookie的设置方式不同:

okhttp调用OkHttpClient的setCookieHandler方法,CookieHandler是Android SDK提供的标注的cookie管理,CookieHandler 的之类CookieManager实现了cookie的具体管理方法,构建CookieManager需要实现CookieStore接口,系统提供了一个默认的实现CookieStoreImpl,只负责把cookie存储在内存中。

  • post消息体构建方式不同

okhttp使用MultipartBuilder,FormEncodingBuilder构建post消息体,最终构建出来的都是RequestBody,而okhttp3增加了RequestBody的子类,构造器放到了RequestBody的子类中,MultipartBody.Builder既可以添加表单数据,也可以添加文件等二进制数据

  • Call和Callback不同

okhttp3 之前用CookieHandler管理cookie

/* cookie管理 */ 
 mCookieHandler = new CookieManager(null, CookiePolicy.ACCEPT_ALL); 
 mOkHttpClient.setCookieHandler(mCookieHandler);

3.0 之后新增了两个类Cookiejar、Cookie两个类,开放接口,需要用户自己去实现cookie的配管理。用户可以直接在CookieJar中简单设置Cookie的管理,如下:

okHttpClientBuilder.cookieJar(new CookieJar() {
       private final HashMap> cookieStore = new HashMap<>();
             @Override
               public void saveFromResponse(HttpUrl url, List cookies) {
                 cookieStore.put(url, cookies);
                }

            @Override
              public List loadForRequest(HttpUrl url) {
                   List cookies = cookieStore.get(url);
                   return cookies != null ? cookies : new ArrayList();
            }
    });
  • OkHttpClient的Cancel方法去掉

3.0之前我们去掉call 可以直接使用mOkHttpClient.cancel(tag);3.0之后直接阉割掉此方法我们可以采用如下方法:

 public void cancelCallsWithTag(Object tag) {
        checkInit();

        if (tag == null) {
            return;
        }

        synchronized (mOkHttpClient.dispatcher().getClass()) {
            for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
                if (tag.equals(call.request().tag())) call.cancel();
            }

            for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
                if (tag.equals(call.request().tag())) call.cancel();
            }
        }
    }

2.Okhttp参数的构造

public class Params {
    public static final String METHOD_GET = "get";
    public static final String METHOD_POST = "post";
    //3个构造参数 一般参数 file head
    private HashMap urlParams = new HashMap<>();
    private HashMap fileParams = new HashMap<>();
    private HashMap headers = new HashMap<>();

    private String api = "";
    private String baseUrl = "";
    private String method;

    public Params() {
        urlParams = new HashMap();
        fileParams = new HashMap();
        headers = new HashMap();
        setBaseUrl(Constants.me().getHost());

        //统一添加请求头
        headers.put("Accept", "application/json");
        headers.put("Version", Constants.me().getVersionName());
        headers.put("Gis-Lat", String.valueOf(Constants.me().getLatitude()));
        headers.put("Gis-Lng", String.valueOf(Constants.me().getLongitude()));

        String token = Constants.me().getToken();
        if (!TextUtils.isEmpty(token)) {
            headers.put("Authorization", "Bearer " + token);
        }
        setMethod(METHOD_POST);
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getApi() {
        return api;
    }

    public void setApi(String api) {
        this.api = api;
    }

    public String getUrl() {
        return baseUrl + api;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }



    public void put(String key, Object value) {
        if (key != null) {
            urlParams.put(key, value);
        }
    }
    public void put(String key, String value) {
        if (key != null) {
            urlParams.put(key, value);
        }
    }

    public void put(String key, int value) {
        if (key != null) {
            urlParams.put(key, String.valueOf(value));
        }
    }

    public void put(String key, double value) {
        if (key != null) {
            urlParams.put(key, String.valueOf(value));
        }
    }
    public void put(String key, float value) {
        if (key != null) {
            urlParams.put(key, String.valueOf(value));
        }
    }

    public void putHeaders(final String key, final int value) {
        this.putHeaders(key, String.valueOf(value));
    }

    public void putHeaders(final String key, final String value) {
        headers.put(key, value);
    }

    /**
     * @param key
     * @param file
     */
    public void put(String key, File file) {
        if (file != null && file.exists()) {
            fileParams.put(key, file);
        }
    }
    //是否为文件
    public boolean isMultipart() {
        return !fileParams.isEmpty();
    }


    public HashMap getUrlParams() {
        return urlParams;
    }

    public HashMap getFileParams() {
        return fileParams;
    }

    public HashMap getHeaders() {
        return headers;
    }

    @Override
    public String toString() {
        return urlParams.toString();
    }
}

3.Okhttp的封装

final public class HttpKit {
    private static final int DEFAULT_MILLISECONDS = 60000; //默认的超时时间

    private OkHttpClient.Builder okHttpClientBuilder;
    private OkHttpClient okHttpClient;
    private Handler mDelivery;
    private Context mContext;
    private final List handlers = new ArrayList<>();//请求返回值处理
    private PersistentCookieStore cookieStore;//永久化保存cookie

    public interface HttpCallback {
        //开始的时候调用,子类可选择实现
        public void onStarted(Request request);
        //当进度条改变的时候,子类可选择实现
        public void onProgressChanged(float progress, long total);

        /**
         * response是否正确
         *
         * @param response
         * @return
         */
        @Deprecated
        public boolean validateReponse(Response response);
        //解析数据,可选择实现,一般子类会自定义一个callback类,去解析
        public T parseNetworkResponse(Response response) throws ApiException;
        //子类回调,可选择实现
        public void onError(ApiException e);
        //子类回调
        public abstract void onResponse(T response);
    }

    private static final HttpKit me = new HttpKit();


    private HttpKit() {
        okHttpClientBuilder = new OkHttpClient.Builder();
        okHttpClientBuilder.connectTimeout(DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
        okHttpClientBuilder.readTimeout(DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
        okHttpClientBuilder.writeTimeout(DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);

        mDelivery = new Handler(Looper.getMainLooper());
    }

    public static HttpKit me() {
        return me;
    }

    //当需要使用cookie的时候,调用
    public static HttpKit init(Context context) {
        me().setContext(context);
        return me();
    }

    private void setContext(Context context) {
        this.mContext = context;
        cookieStore = new PersistentCookieStore(mContext);//永久化保存cookie
        CookieJarImpl cookieJar = new CookieJarImpl(cookieStore);
        okHttpClientBuilder.cookieJar(cookieJar);
    }
    //设置cookie
    public void setCookie(Uri uri, Cookie cookie) {
        HttpUrl httpUrl = new HttpUrl.Builder().scheme(uri.getScheme()).host(uri.getHost()).build();
        cookieStore.add(httpUrl, cookie);
    }

    public void removeAllCookie() {
        cookieStore.removeAll();
    }

    //本地拦截器
    public HttpKit addInterceptor(Interceptor interceptor) {
        okHttpClientBuilder.addInterceptor(interceptor);
        return this;
    }
    //网络拦截器
    public HttpKit addNetworkInterceptor(Interceptor interceptor) {
        okHttpClientBuilder.addNetworkInterceptor(interceptor);
        return this;
    }


    public List handlers() {
        return handlers;
    }

    public HttpKit addHandler(ResponseHandler handler) {
        handlers.add(handler);
        return this;
    }

    public Handler getDelivery() {
        return mDelivery;
    }

    public void build() {
        okHttpClient = okHttpClientBuilder.build();
    }

    private Request buildRequest(Params params) {
        Request.Builder builder = new Request.Builder();
        builder.url(params.getUrl());
        //头
        if (!params.getHeaders().isEmpty()) {
            for (Map.Entry header : params.getHeaders().entrySet()) {
                if (header.getKey() != null) {
                    builder.addHeader(header.getKey(), header.getValue());
                }
            }
        }
        //文件表单上传
        if (params.isMultipart()) {
            MultipartBody.Builder body = new MultipartBody.Builder();
            body.setType(MultipartBody.FORM);
            //有url
            if (!params.getUrlParams().isEmpty()) {
                for (Map.Entry param : params.getUrlParams().entrySet()) {
                    if (param.getKey() != null) {
                        body.addFormDataPart(param.getKey(), (String) param.getValue());
                    }
                }
            }
            //有file对象
            for (Map.Entry param : params.getFileParams().entrySet()) {
                File file = param.getValue();
                if (file != null && file.exists()) {
                    RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
                    body.addFormDataPart(param.getKey(), file.getName(), fileBody);
                }
            }
            builder.post(body.build());
            //不是表单,是一般的Post请求的话
        } else if (Params.METHOD_POST.equals(params.getMethod())) {
            FormBody.Builder body = new FormBody.Builder();
            body.add("i", CryptKit.encrypt(params.getUrlParams(), params.getUrl()));
            builder.post(body.build());
        }
        return builder.build();
    }

    //同步请求
    public Response execute(Params params) throws IOException {
        Request request = buildRequest(params);

        Call call = okHttpClient.newCall(request);
        return call.execute();
    }

    /**
     * get请求不做parseNetworkResponse处理,原数据返回
     *
     * @param params
     * @param callback
     */
    public void get(Params params, final HttpCallback callback) {
        Request request = buildRequest(params);

        if (callback != null) callback.onStarted(request);
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                sendFail(new ApiException(e), callback);
            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    if (call.isCanceled()) {
                        sendFail(new ApiException("取消", -1), callback);
                        return;
                    }

                    Object o = callback.parseNetworkResponse(response);
                    sendSuccess(o, callback);
                } catch (ApiException e) {
                    sendFail(e, callback);
                } finally {
                    if (response.body() != null)
                        response.body().close();
                }
            }
        });
    }

    public void post(final Params params, final HttpCallback callback) {
        if (params == null || callback == null) {
            Log4a.e("post params null");
            return;
        }
        Request request = buildRequest(params);

        if (callback != null) callback.onStarted(request);
        Call call = okHttpClient.newCall(request);
        Log4a.e("======>post "+params.getUrl());
        Log4a.e("======>   params:"+params.toString());
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                sendFail(new ApiException(e.getCause()), callback);
            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    if (call.isCanceled()) {
                        sendFail(new ApiException("取消", -1), callback);
                        return;
                    }

                    Object o = callback.parseNetworkResponse(response);
                    sendSuccess(o, callback);
                } catch (ApiException e) {
                    sendFail(e, callback);
                } finally {
                    if (response.body() != null)
                        response.body().close();
                }
            }
        });
    }

    private void sendFail(final ApiException e, final HttpCallback callback) {
        if (callback == null) return;

        mDelivery.post(new Runnable() {
            @Override
            public void run() {
                try {
                    if (callback != null) {
                        callback.onError(e);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void sendSuccess(final Object object, final HttpCallback callback) {
        if (callback == null) return;

        mDelivery.post(new Runnable() {
            @Override
            public void run() {
                try {
                    if (callback != null && object != null) {
                        callback.onResponse(object);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

4.子类自定义CallBack方法执行相应的操作,例如解析数据等

public abstract class JSONCallback extends TypeToken implements HttpKit.HttpCallback {

    private Type mClass;//获取类似List或者 Student的type

    public JSONCallback() {
        mClass = getType();
    }

    public void onStarted(Request request) {
    }

    public void onProgressChanged(float progress, long total) {

    }

    /**
     * response是否正确
     *
     * @param response
     * @return
     */
    @Deprecated
    public boolean validateReponse(Response response) {
        return true;
    }

    public T parseNetworkResponse(Response response) throws ApiException {
        String resp = "";
        String data = "";
        int status;
        String message;

        try {
            resp = response.body().string();
            Log4a.e("======>> response:"+response.request().url().url());
            Log4a.json(resp);
        } catch (IOException e) {
            throw new ApiException(e);
        }

        try {
            JSONObject jsonObject = new JSONObject(resp);
            status = jsonObject.getInt("code");
            message = jsonObject.getString("message");
            if (status == 1000 && jsonObject.has("data")) {
                data = jsonObject.getString("data");
            }
        } catch (JSONException e) {
            throw new ApiException(e);
        }

        List handlers = HttpKit.me().handlers();
        if (handlers != null && handlers.size() > 0) {
            for (ResponseHandler handler : handlers)
                handler.onHandler(status, message, response.request().url().url().getPath());
        }

        if (status != 1000) {
            throw new ApiException(message, status);
        }

        try {
            if (GsonKit.isSubObjectOf(mClass, List.class)) {
                if ("".equals(data) || data == null||"{}".equals(data)) {
                    data = "[]";
                }
            } else {
                if ("".equals(data) || data == null||"[]".equals(data)) {
                    data = "{}";
                }
            }
            return GsonKit.fromJson(data, mClass);
        } catch (Exception e) {
            throw new ApiException(message, status, e);
        }
    }

    public void onError(ApiException e) {
        if (e.getStatus() == 0)
            ViewKit.shortToast("联网失败,请检查网络");
        else if (e.getStatus() == -1) {// TODO: 2016/11/26

        } else if (!StringKit.isEmpty(e.getMessage()))
            ViewKit.shortToast(e.getMessage());
    }

    public abstract void onResponse(T response);
}

5.Cookie的一些设置

//当需要使用cookie的时候,调用
    public static HttpKit init(Context context) {
        me().setContext(context);
        return me();
    }

    private void setContext(Context context) {
        this.mContext = context;
        cookieStore = new PersistentCookieStore(mContext);//永久化保存cookie
        CookieJarImpl cookieJar = new CookieJarImpl(cookieStore);
        okHttpClientBuilder.cookieJar(cookieJar);
    }
    //设置cookie
    public void setCookie(Uri uri, Cookie cookie) {
        HttpUrl httpUrl = new HttpUrl.Builder().scheme(uri.getScheme()).host(uri.getHost()).build();
        cookieStore.add(httpUrl, cookie);
    }

    public void removeAllCookie() {
        cookieStore.removeAll();
    }

CookieJarImpl的实现,PersistentCookieStore的永久化代码,网上有,直接搜

public class CookieJarImpl implements CookieJar {
    private CookieStore cookieStore;

    public CookieJarImpl(CookieStore cookieStore) {
        if (cookieStore == null)
            throw new IllegalArgumentException(String.format("cookieStore can not be null."));
        this.cookieStore = cookieStore;
    }

    @Override
    public synchronized void saveFromResponse(HttpUrl url, List cookies) {
        cookieStore.add(url, cookies);
    }

    @Override
    public synchronized List loadForRequest(HttpUrl url) {
        return cookieStore.get(url);
    }

    public CookieStore getCookieStore() {
        return cookieStore;
    }
}

你可能感兴趣的:(Android之Okhttp的封装)