oKHttp基本封装

需求:

  • get请求和post请求,上传文件和下载文件时返回进度
  • oKHttpClient实例只创建一次
  • 如果用户在结果还未返回时又连续多次请求相同的api,只保留最后一次,前面的中断请求
  • 返回的JSON数据转化成实体对象
  • 访问服务器是异步请求,将请求结果回调到主线程

首先用一个抽象类用于回调

public abstract class ResultCallback {
    public abstract void onError(Request request,Exception e);
    public abstract void onSuccess(Object str);
}

oKHttp无论哪种方式请求都是创建OkHttpClient、Request和Call对象,然后在调用Call的enqueue()方法。

 private volatile static oKHttpEngine mInstance;
 private oKHttpEngine(){}

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

使用单例设计模式,获取类的对象,由于是单例设计模式,所以无论对getInstance()调用多少次都只会创建一个对象

public void setHttpConfig(HttpConfig httpConfig){
        this.httpConfig = httpConfig;
        client = new OkHttpClient.Builder()
                .connectTimeout(httpConfig.getConnectionTimeOut(), TimeUnit.SECONDS)
                .readTimeout(httpConfig.getReadTmeOut(),TimeUnit.SECONDS)
                .writeTimeout(httpConfig.getWriteTimeOut(),TimeUnit.SECONDS)
                .proxy(Proxy.NO_PROXY)
                .build();
        mHandler = new Handler();
        gson = new Gson();
}

创建oKHttpClient对象,并设置链接时间,读取时间等信息,此方法必须被调用。并创建Gson对象和Handler对象。

private Call execute(Request.Builder builder,Header[] h, ResultCallback resultCallback,String url){
        //设置请求头信息
        boolean hasUa = false;
        if(h==null){
            builder.header("Connection","close");
            builder.header("Accept","*/*");
        }else {
            for (Util.Header header:h){
                builder.header(header.getName(),header.getValue());
                if(!hasUa&&header.getName().equals("User-Agent")){
                    hasUa = true;
                }
            }
        }
        if(!hasUa&&!TextUtils.isEmpty(httpConfig.getUserAgent())){
            builder.header("User-Agent",httpConfig.getUserAgent());
        }
        Call call = client.newCall(builder.build());
        dealResult(call,resultCallback,url);
        return call;
    }

首先设置请求头信息,通常不需要设置,通过build()方法创建Request对象,并且创建Call对象

private void dealResult(Call call, final ResultCallback resultCallback, final String url){
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call,IOException e) {
                sendFailed(call.request(),resultCallback,e);
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if(resultCallback!=null){
                    try {
                        String str = response.body().string();
                        if(clazz!=null||clazzBean!=null){
                            JSONObject jsonObject = new JSONObject(str);
                            String strData = jsonObject.toString();
                            //用于解析JSON中的数组
                            if(info!=null){
                                JSONArray jsonArray = jsonObject.getJSONArray(info);
                                if(jsonArray.length()>0){
                                    for(int i =0;i//用于解析JSON数据中去除数组的部分
                            if(clazzBean!=null){
                                Object o = gson.fromJson(strData,clazzBean);
                                sendSuccess(o,resultCallback);
                            }
                        }else {
                            sendSuccess(str,resultCallback);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }catch (JSONException e){
                        e.printStackTrace();
                    }
                }else {
                    try {
                        ResponseBody requestBody = ProgressHelper.withProgress(response.body(),progressListener);
                        BufferedSource bufferedSource = requestBody.source();
                        File file = new File(saveFilePath);
                        file.delete();
                        file.getParentFile().mkdirs();
                        file.createNewFile();
                        BufferedSink sink = Okio.buffer(Okio.sink(file));
                        bufferedSource.readAll(sink);
                        sink.flush();
                        bufferedSource.close();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }

            private void sendSuccess(final Object o, final ResultCallback resultCallback){
                if(resultCallback!=null){
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            resultCallback.onSuccess(o);
                        }
                    });
                }
            }

            private void sendFailed(final Request request, final ResultCallback resultCallback, final Exception e){
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(resultCallback!=null){
                            resultCallback.onError(request,e);
                        }else {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }

如果下载文件则不需要设置回调,故ResultCallback设置为null,这里上传和下载文件的监听使用的是开源库https://github.com/lizhangqu/CoreProgress,在请求数据时若返回的是JSON数据,首先解析JSON数组,然后解析非数组的部分。注意这里的数据解析在子线程中运行,当解析完毕后才把数据发送给主线程回调

get请求:

 public void asyncGet(String url,Header[] h,ResultCallback resultCallback,Class clazz,Class clazzBean,String info){
        this.clazz = clazz;
        this.clazzBean = clazzBean;
        this.info = info;
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        Call call = execute(builder,h,resultCallback,url);
        add(url,call);
    }

post请求:

public void post(String url, Header[] h, ResultCallback resultCallback, List list,Class clazz,Class clazzBean,String info){
        if(list == null){
             list = new ArrayList<>();
        }
        this.clazz = clazz;
        this.clazzBean = clazzBean;
        this.info = info;
        list.addAll(httpConfig.getComFiled());
        FormBody.Builder form = new FormBody.Builder();
        for(NameValue item:list){
            form.add(item.getName(),item.getValue());
        }
        RequestBody requestBody = form.build();
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        builder.post(requestBody);
        Call call = execute(builder,h,resultCallback,url);
        add(url,call);
    }

上传JSON:

public void jsonPost(String url,Header[] h,ResultCallback resultCallback,Map<String,String> map,Class clazz,Class clazzBean,String info){
        this.info = info;
        this.clazzBean = clazzBean;
        this.clazz = clazz;
        String str = gson.toJson(map);
        MediaType Json = MediaType.parse("application/json; charset=utf-8");
        RequestBody requestBody = RequestBody.create(Json,str);
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        builder.post(requestBody);
        Call call = execute(builder,h,resultCallback,url);
        add(url,call);
    }

上传文件:

public void postFile(String url, Header[] h, ResultCallback resultCallback, Set files, Class clazz, Class clazzBean, String info, String key, ProgressUIListener progressUIListener){
        this.clazz = clazz;
        this.clazzBean = clazzBean;
        this.info = info;
        MediaType mediaType = MediaType.parse("application/octet-stream");
        MultipartBody.Builder mBuilder = new MultipartBody.Builder();
        mBuilder.setType(MultipartBody.FORM);
        if(files!=null){
            for(File file:files){
                mBuilder.addFormDataPart(key,file.getName(),RequestBody.create(mediaType,file));
            }
        }
        RequestBody requestBody = null;
        if(progressUIListener!=null){//需要回调上传进度
            requestBody = ProgressHelper.withProgress(mBuilder.build(),progressUIListener);
        }else {//不需要回调上传进度
            requestBody = mBuilder.build();
        }
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        builder.post(requestBody);
        Call call = execute(builder,h,resultCallback,url);
        add(url,call);
    }

下载文件:

public void downloadFile(String url,Header[] h,ResultCallback resultCallback,String saveFilePath,ProgressUIListener progressUIListener){
        this.progressListener = progressUIListener;
        this.saveFilePath = saveFilePath;
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        Call call = execute(builder,h,resultCallback,url);
        add(url,call);
    }
private void add(String url,Call call){
        if(!TextUtils.isEmpty(url)){
            if(url.contains("?")){
                url = url.substring(0,url.indexOf("?"));
            }
            cancel(url);
            map.put(url,call);
        }
    }

    private void cancel(String url){
        Call call = map.remove(url);
        if(call!=null){
            call.cancel();
        }
    }

首先将URL和Call对象添加到map集合中,当从map中取出Call不为null时则取消请求,在第一次请求时,首先从集合中取出Call对象,由于是第一次请求故Call为null,当进行第二次相同的请求时,此时从集合中取出的是第一次请求的Call对象,故调用cancel()方法取消该请求。

全部代码OKHTTP封装2

你可能感兴趣的:(网络)