原生okhttp网络框架得封装

我怕爱的太早我们不能终老 提交于 2019-12-27 04:09:18

前文:现在的网络框架中最火的是retrofit与okhttp,retrofit看了一部分,封装了,但是看大部分都是与rxjava一起使用,而很多大神也对okhttp做了一层包装,封装出一些网络框架,像okgo,okhttpUtils,但是别人封装的再华丽,不代表适合自己,所以本wolf分享一篇原生封装的okhttp。

首先,需要导入gradle :

implementation 'com.squareup.okhttp3:okhttp:3.4.1'

okhttp则分为Request请求与response响应。

request请求体:每一个HTTP请求中都应该包含一个URL,一个GET或POST方法以及Header或其他参数,当然还可以含特定内容类型的数据流。

response 响应码:响应则包含一个回复代码(200代表成功,404代表未找到),Header和定制可选的body。

okhttp配置:

包括设置响应时间,读取时间等,先配置了,便可使用。

  private final OkHttpClient client;
  client = new OkHttpClient.Builder()
                .connectTimeout(60000, TimeUnit.MILLISECONDS)
                .writeTimeout(60000, TimeUnit.MILLISECONDS)
                .readTimeout(60000, TimeUnit.MILLISECONDS)
                .build();

基本请求:GET 请求 ,POST请求

GET请求

 Request.Builder builder = new Request.Builder();
        Request request = builder.get().url(url).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException error) {
               //响应失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //响应成功
            }
        });

POST请求:

JSON格式传输数据:

RequestBody body = RequestBody.create(JSON, jsonObject.toString());
 client.newCall(
                new Request.Builder()
                        .url(url)
                        //      .headers()//添加头
                        .post(body)
                        .build()).enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
               
                
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                LogUtil.i("http response " + response);
                if (response.isSuccessful()) {

                 
                    }
                }else {
                   
                }
            }
        });

 

可以看出来,json传输,需要把jsonObject转成json串,放到RequestBody中,再请求okhttp中自带的CallBack即可。

 

表单传输:

OkHttpClient client = new OkHttpClient();
MultipartBody multipartBody =new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("groupId",""+groupId)//添加键值对参数
        .addFormDataPart("title","title")
        .addFormDataPart("file",file.getName(),RequestBody.create(MediaType.parse("file/*"), file))//添加文件
        .build();
final Request request = new Request.Builder()
        .url(URLContant.CHAT_ROOM_SUBJECT_IMAGE)
        .post(multipartBody)
        .build();
client.newCall(request).enqueue(new Callback() {//此处省略回调});

按照okhttp原生写法为此。还有传byte数组,流数据的,应用较少。

 okhttp设置头文件:

Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .header("User-Agent", "OkHttp Headers.java")
                .addHeader("token", "myToken")
                .build();

 

okhttp原生写法很简单,但是使用中,需要自己做一层封装,并且在使用中容易遇到很多问题,像多次点击,点击一次请求了,回调没回来,又点击了进行请求,可能会导致出错。原生写法,没有进行封装,使用起来很不方便,分享一下,我对okhttp做的封装。

CancelAble 类,方便取消请求

public class CancelAble {

    Call call;

    public void cancel(){
        if(call != null){
            call.cancel();
            call = null;
        }
    }

}

Subscriber回调类

public interface Subscriber<T> {

    void onCompleted(T result);

    void onError(Throwable e);

    Class<?> getType();
}

自己封装的okhttpCallBack类,方便回调

public class OkHttpCallback implements okhttp3.Callback {
    private static final String TAG = "OkHttpCallback";
    private Subscriber subscriber;
    private Class<? extends BaseBean> type;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private Gson gson;
    String body;

    public OkHttpCallback(@NonNull Subscriber subscriber) {
        this.subscriber = subscriber;
        type = subscriber.getType();

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response == null) {
            return;
        }

        body = response.body().string();
        if (subscriber != null) {
            if (type == null){
                subscriber.onError(new Exception("type can't be null"));
                return;
            }
            if ("String".equals(type.getSimpleName())) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        subscriber.onCompleted(body);
                    }
                });
            } else {
            gson = new Gson();
            try {
                final BaseBean bean = gson.fromJson(body, type);
                if (bean != null) {

                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            subscriber.onCompleted(bean);
                        }
                    });

                }
            } catch (final Exception e) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        subscriber.onError(e);
                    }
                });
            }
        }
        }
    }

    @Override
    public void onFailure(Call call, final IOException e) {
        if (subscriber != null) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    subscriber.onError(e);
                }
            });
        }
    }
}

 

get请求方法封装:

   public CancelAble get(String url, final OkHttpCallback callback) {
        cleanCancelAbleList();
        Request.Builder builder = new Request.Builder();
        Request request = builder.get().url(url).build();
        CancelAble cancelAble = new CancelAble();
        cancelAble.call = client.newCall(request);
        cancelAble.call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException error) {
                if (callback == null) return;
                if (call.isCanceled()) return;
                callback.onFailure(call, error);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                callback.onResponse(call, response);
            }
        });
        return cancelAble;
    }

post请求方法封装(json):

 public CancelAble post(String url, JSONObject jsonObject, OkHttpCallback callback) {
        cleanCancelAbleList();
        Request request = getStringPostRequest(url, jsonObject);
        Log.d(TAG, "接口post:" + url + (jsonObject == null ? "" : jsonObject.toString()));
        CancelAble cancelAble = new CancelAble();
        cancelAble.call = client.newCall(request);
        callList.add(new WeakReference<>(cancelAble));

        execCallback(cancelAble.call, callback);
        return cancelAble;
    }


    private void execCallback(Call call, final OkHttpCallback callback) {
        call.enqueue(new Callback() {
            public void onResponse(final Call call, final Response response) throws IOException {
                callback.onResponse(call, response);
            }

            public void onFailure(Call call, IOException e) {
                Log.e(TAG, "onFailure", e);
                if (callback == null) return;
                if (call.isCanceled()) return;
                callback.onFailure(call, e);
            }
        });
    }

表单请求,带file

 public void postPic(String url, Map<String, String> map, Map<String, File> paths, final OkHttpCallback callback) {
        cleanCancelAbleList();
        Request.Builder builder = new Request.Builder();
        builder.url(url);

        //TODO 传递过来的集合必须做逻辑判断,不能为空,否则下面报空指针
        MultipartBody.Builder multiBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);
        //遍历map中所有参数到builder
        if (map != null && map.size() != 0) {
            if (map.keySet() != null && map.keySet().size() != 0) {
                for (String key : map.keySet()) {
                    if (key != null) {//可以是空串
                        String value = map.get(key);
                        if (value != null) {
                            multiBuilder.addFormDataPart(key, value);
                        }
                    }
                }
            }
        }
        //遍历paths中所有图片绝对路径到builder,并约定key如“upload”作为后台接受多张图片的key
        if (paths != null && paths.size() != 0) {
            if (paths.keySet() != null && paths.keySet().size() != 0) {
                for (String name : paths.keySet()) {
                    if (name != null && !"".equals(name)) {//空串无意义
                        File imgPath = paths.get(name);
                        //TODO 文件路径不能为空
                        if (imgPath != null && !"".equals(imgPath)) {
                            multiBuilder.addFormDataPart(name, "file.png", RequestBody.create(MEDIA_TYPE_PNG, imgPath));
                        }
                    }
                }


            }
        }


        builder.post(multiBuilder.build());

        Request request = builder.build();
        Call postCall = client.newCall(request);
        postCall.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException error) {
                Log.i("xjz", error.toString());
                if (callback == null) return;
                if (call.isCanceled()) return;
                callback.onFailure(call, error);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                getJsonData(response, requestCode, paramsMaps, mHandler);
                Log.i("xjz", response.toString());
                callback.onResponse(call, response);
            }
        });
    }

 

完整的Okutils类:


public class OKUtils {
    private final OkHttpClient client;
    private final ArrayList<WeakReference<CancelAble>> callList = new ArrayList<>(0);
    private static final String TAG = "okhttp";
    public static final OKUtils okClient = new OKUtils();
    private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");


    public OKUtils() {
        client = new OkHttpClient.Builder()
                .connectTimeout(60000, TimeUnit.MILLISECONDS)
                .writeTimeout(60000, TimeUnit.MILLISECONDS)
                .readTimeout(60000, TimeUnit.MILLISECONDS)
                .build();
    }

    public static OKUtils getInstance() {
        return okClient;
    }


    public CancelAble post(String url, JSONObject jsonObject, OkHttpCallback callback) {
        cleanCancelAbleList();
        Request request = getStringPostRequest(url, jsonObject);
        Log.d(TAG, "接口post:" + url + (jsonObject == null ? "" : jsonObject.toString()));
        CancelAble cancelAble = new CancelAble();
        cancelAble.call = client.newCall(request);
        callList.add(new WeakReference<>(cancelAble));

        execCallback(cancelAble.call, callback);
        return cancelAble;
    }

    public CancelAble get(String url, final OkHttpCallback callback) {
        cleanCancelAbleList();
        Request.Builder builder = new Request.Builder();
        Request request = builder.get().url(url).build();
        CancelAble cancelAble = new CancelAble();
        cancelAble.call = client.newCall(request);
        cancelAble.call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException error) {
                if (callback == null) return;
                if (call.isCanceled()) return;
                callback.onFailure(call, error);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                callback.onResponse(call, response);
            }
        });
        return cancelAble;
    }
    /**
     * 直接传file
     * @param url
     * @param map
     * @param paths
     * @param callback
     */
    public void postPic(String url, Map<String, String> map, Map<String, File> paths, final OkHttpCallback callback) {
        cleanCancelAbleList();
        Request.Builder builder = new Request.Builder();
        builder.url(url);

        //TODO 传递过来的集合必须做逻辑判断,不能为空,否则下面报空指针
        MultipartBody.Builder multiBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);
        //遍历map中所有参数到builder
        if (map != null && map.size() != 0) {
            if (map.keySet() != null && map.keySet().size() != 0) {
                for (String key : map.keySet()) {
                    if (key != null) {//可以是空串
                        String value = map.get(key);
                        if (value != null) {
                            multiBuilder.addFormDataPart(key, value);
                        }
                    }
                }
            }
        }
        //遍历paths中所有图片绝对路径到builder,并约定key如“upload”作为后台接受多张图片的key
        if (paths != null && paths.size() != 0) {
            if (paths.keySet() != null && paths.keySet().size() != 0) {
                for (String name : paths.keySet()) {
                    if (name != null && !"".equals(name)) {//空串无意义
                        File imgPath = paths.get(name);
                        //TODO 文件路径不能为空
                        if (imgPath != null && !"".equals(imgPath)) {
                            multiBuilder.addFormDataPart(name, "file.png", RequestBody.create(MEDIA_TYPE_PNG, imgPath));
                        }
                    }
                }


            }
        }


        builder.post(multiBuilder.build());

        Request request = builder.build();
        Call postCall = client.newCall(request);
        postCall.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException error) {
                Log.i("xjz", error.toString());
                if (callback == null) return;
                if (call.isCanceled()) return;
                callback.onFailure(call, error);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                getJsonData(response, requestCode, paramsMaps, mHandler);
                Log.i("xjz", response.toString());
                callback.onResponse(call, response);
            }
        });
    }


    public void cancelAll() {
        for (WeakReference<CancelAble> item : callList)
            if (item.get() != null)
                item.get().cancel();
        callList.clear();
    }

    private void cleanCancelAbleList() {
        if (callList.size() <= client.dispatcher().getMaxRequests())
            return;
        ArrayList<WeakReference> readyRemoveList = new ArrayList<>(callList.size());
        for (WeakReference<CancelAble> item : callList)
            if (item.get() == null)
                readyRemoveList.add(item);
        callList.removeAll(readyRemoveList);
    }

    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    private Request getStringPostRequest(String url, JSONObject jsonObject) {
        RequestBody body = RequestBody.create(JSON, jsonObject.toString());
        return new Request.Builder()
                .url(url)
                .post(body)
                .build();
    }


    private void execCallback(Call call, final OkHttpCallback callback) {
        call.enqueue(new Callback() {
            public void onResponse(final Call call, final Response response) throws IOException {
                callback.onResponse(call, response);
            }

            public void onFailure(Call call, IOException e) {
                Log.e(TAG, "onFailure", e);
                if (callback == null) return;
                if (call.isCanceled()) return;
                callback.onFailure(call, e);
            }
        });
    }



}

使用则是一行代码,请求回调,适合MVC模式,MVP自己回调就好。

  OKUtils.getInstance().post(url,jsonObject,new OkHttpCallback(new Subscriber<StoreManageBean>() {
            @Override
            public void onCompleted(StoreManageBean result) {
//                result.toString();
            }

            @Override
            public void onError(Throwable e) {
                e.toString();
            }

            @Override
            public Class<?> getType() {
                return StoreManageBean.class;
            }
        }));
    }

使用起来非常简单,逻辑也会很清晰。

资源下载地址:https://download.csdn.net/download/xjz123456qqq/12054325

本篇有啥问题的,请及时留言指出,欢迎指正,共同进步。

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!