美文网首页Android进阶之路RxJAva OKHttp RetrofitAndroid技术进阶
开源项目OkHttpPlus——OkHttp封装库,支持GET、

开源项目OkHttpPlus——OkHttp封装库,支持GET、

作者: 裸奔的凯子哥 | 来源:发表于2015-11-24 18:47 被阅读3005次

    OkHttpPlus介绍

    项目地址:https://github.com/ZhaoKaiQiang/OkHttpPlus

    主要功能:OkHttp封装,支持GET、POST、UI线程回调、JSON格式解析、链式调用、小文件上传下载及进度监听等功能

    为什么要写这么一个库呢?

    首先,是因为OkHttp在4.4之后已经作为底层的Http实现了,所以OkHttp这个库很强大,值得我们学习。

    其次,在我看来,OkHttp使用起来不如Volley方便,OkHttp的回调都是在工作线程,所以如果在回调里面操作View的话,需要自己转换到UI线程,非常繁琐,所以需要封装。也有将OkHttp作为Volley底层Http实现的用法,发送请求、维护请求队列用的是Volley,实际的Http请求用的是OkHttp。

    关于Volley和oOkHttp结合的Demo请戳煎蛋项目

    如何使用

    初始化

    你可以在Application里面完成初始化,因为对OkHttp的封装主要使用的是代理设计模式,使用OkHttpProxy.getInstance()可以获取到单例客户端,你可以像没封装之前一样,设置任意的参数,比如下面就设置超时时间和忽略HTTPS认证。

    public class OkApplication extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            OkHttpClient okHttpClient = OkHttpProxy.getInstance();
            okHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
            okHttpClient.setReadTimeout(15, TimeUnit.SECONDS);
            okHttpClient.setWriteTimeout(15, TimeUnit.SECONDS);
    
            //ignore HTTPS Authentication
            okHttpClient.setHostnameVerifier(new MyHostnameVerifier());
            try {
                SSLContext sc = SSLContext.getInstance("TLS");
                sc.init(null, new TrustManager[]{new MyTrustManager()}, new SecureRandom());
                okHttpClient.setSslSocketFactory(sc.getSocketFactory());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
        }
    }
    

    Get方法

    你大多数情况下是和OkHttpProxy这个代理类打交道,而且OkHttpPlus支持链式调用,内部采用Builder设计模式,所以你可以像下面这样使用

     OkHttpProxy.get()
                    .url(URL_USER)
                    .tag(this)
                    .execute(new OkCallback<User>(new OkJsonParser<User>() {
                    }) {
                        @Override
                        public void onSuccess(int code, User user) {
                            tv_response.setText(user.toString());
                        }
    
                        @Override
                        public void onFailure(Throwable e) {
                            tv_response.setText(e.getMessage());
                        }
                    });
    

    为了支持返回值解析,这里我采用了泛型,在OkCallback的构造函数中,你需要传入一个解析器,OkHttpPlus内部支持5种解析器,这可以解决你大部分的需求

    • OkBaseParser,所有解析器的基类,不可直接使用
    • OkBaseJsonParser,所有JSON解析器的基类,你可以继承它来定义自己的JSON解析
    • OkJsonParser,JSON解析器,支持JSONObject和JSONArray的解析,默认使用GSON作为解析器
    • OkTextParser,String解析器,支持将结果以String方式输出
    • OkFileParser,文件解析器,支持将结果保存为文件,你可以用来下载文件,但是不支持较大文件下载

    所以如果你想获取一个JSONArray,你可以像下面这样

     OkHttpProxy.get()
                    .url(URL_USER)
                    .tag(this)
                    .execute(new OkCallback<List<User>>(new OkJsonParser<List<User>>() {
                    }) {
                        @Override
                        public void onSuccess(int code, List<User> users) {
                            tv_response.setText(users.toString());
                        }
    
                        @Override
                        public void onFailure(Throwable e) {
                            tv_response.setText(e.getMessage());
                        }
                    });
    

    你如果想获取String数据,你可以这样

      OkHttpProxy.get()
                    .url(URL_BAIDU)
                    .tag(this)
                    .execute(new OkCallback<String>(new OkTextParser()) {
                        @Override
                        public void onSuccess(int code, String s) {
                            tv_response.setText(s);
                        }
    
                        @Override
                        public void onFailure(Throwable e) {
                            tv_response.setText(e.getMessage());
                        }
                    });
    

    当然,如果你想自定义一个解析器,也是完全可以的。

    OkHttpPlus的解析器部分使用的是策略设计模式,所以你可以像下面这样自定义一个解析策略,完成结果的解析

    public class JokeParser<T> extends OkJsonParser<T> {
    
        @Nullable
        @Override
        public T parse(Response response) throws IOException {
            String jsonStr = response.body().string();
            try {
                jsonStr = new JSONObject(jsonStr).getJSONArray("comments").toString();
                return mGson.fromJson(jsonStr, new TypeToken<ArrayList<Joke>>() {
                }.getType());
            } catch (JSONException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    

    然后就可以将返回结果解析为ArrayList<Joke>了

      OkHttpProxy.get()
                    .url(Joke.getRequestUrl(1))
                    .tag(this).execute(new OkCallback<List<Joke>>(new JokeParser()) {
                @Override
                public void onSuccess(int code, List<Joke> jokes) {
                    tv_response.setText(jokes.toString());
                }
    
                @Override
                public void onFailure(Throwable e) {
                    tv_response.setText(e.getMessage());
                }
            });
    

    Post方法

    Post的方法与Get方法使用类似,你可以像下面这样发送POST请求,并添加Header和Params。

     OkHttpProxy
                    .post()
                    .url(URL_USERS)
                    .tag(this)
                    .addParams("name", "zhaokaiqiang")
                    .addHeader("header", "okhttp")
                    .execute(new OkCallback<ArrayList<User>>(new OkJsonParser<ArrayList<User>>() {
                    }) {
                        @Override
                        public void onSuccess(int code, ArrayList<User> users) {
                            tv_response.setText(users.toString());
                        }
    
                        @Override
                        public void onFailure(Throwable e) {
                            tv_response.setText(e.getMessage());
                        }
                    });
    

    你可能注意到了,在发送每个请求的时候,我都调用了tag()方法,所以你可以在不需要的时候,将请求取消掉。

    @Override
        protected void onDestroy() {
            super.onDestroy();
            OkHttpProxy.cancel(this);
        }
    

    下载

    你可以像下面这样下载一个文件,但是由于下载的内容都在内存中,所以不支持大文件下载,否则会OOM

     String desFileDir = Environment.getExternalStorageDirectory().getAbsolutePath();
            OkHttpProxy.download(URL_DOWMLOAD, new DownloadListener(desFileDir, "json.jar") {
    
                @Override
                public void onUIProgress(Progress progress) {
                    //当下载资源长度不可知时,progress.getTotalBytes()为-1,此时不能显示下载进度
                    int pro = (int) (progress.getCurrentBytes() / progress.getTotalBytes() * 100);
                    if (pro > 0) {
                        pb.setProgress(pro);
                    }
                    KLog.d("pro = " + pro + " getCurrentBytes = " + progress.getCurrentBytes() + " getTotalBytes = " + progress.getTotalBytes());
                }
    
                @Override
                public void onSuccess(File file) {
                    tv_response.setText(file.getAbsolutePath());
                }
    
                @Override
                public void onFailure(Exception e) {
                    tv_response.setText(e.getMessage());
                }
            });
        }
    

    上传

    OkHttpPlus也支持小文件上传,我这里测试使用的是七牛的上传API,Token是有期限的,所以你需要在下面网址自己生成测试

     /**
         * 采用七牛上传接口,Token有效期为12小时,若Token无效,请在下面自行获取
         * Token生成网址 http://jsfiddle.net/gh/get/extjs/4.2/icattlecoder/jsfiddle/tree/master/uptoken
         * <p/>
         * AK = IUy4JnOZHP6o-rx9QsGLf9jMTAKfRkL07gNssIDA
         * CK = DkfA7gPTNy1k4HWnQynra3qAZhrzp-wmSs15vub6
         * BUCKE_NAME = zhaokaiqiang
         */
        public void uploadFile(View view) {
    
            File file = new File(Environment.getExternalStorageDirectory(), "jiandan02.jpg");
            if (!file.exists()) {
                Toast.makeText(MainActivity.this, "文件不存在,请修改文件路径", Toast.LENGTH_SHORT).show();
                return;
            }
    
            Map<String, String> param = new HashMap<>();
            param.put("token", TOKEN);
            Pair<String, File> pair = new Pair("file", file);
    
            OkHttpProxy
                    .upload()
                    .url(URL_UPLOAD)
                    .file(pair)
                    .setParams(param)
                    .setWriteTimeOut(20)
                    .start(new UploadListener() {
                        @Override
                        public void onSuccess(Response response) {
                            tv_response.setText("isSuccessful = " + response.isSuccessful() + "\n" + "code = " + response.code());
                        }
    
                        @Override
                        public void onFailure(Exception e) {
                            tv_response.setText(e.getMessage());
                        }
    
                        @Override
                        public void onUIProgress(Progress progress) {
                            int pro = (int) ((progress.getCurrentBytes() + 0.0) / progress.getTotalBytes() * 100);
                            if (pro > 0) {
                                pb.setProgress(pro);
                            }
                            KLog.d("pro = " + pro + " getCurrentBytes = " + progress.getCurrentBytes() + " getTotalBytes = " + progress.getTotalBytes());
                        }
                    });
        }
    

    灵感来源

    本项目的灵感和部分代码来自于下面两个开源项目,谢谢他们的分享精神


    尊重原创,转载请注明:From 凯子哥 侵权必究!

    相关文章

      网友评论

      • cb550b8c966b:不支持session的保持吧
      • 空心菜的爱:叼叼的凯子哥
      • 最最最最醉人:为什么Github上说不适合用于工程中呢?正式版什么时候发布呢?
        裸奔的凯子哥: @这种重中之重重中之重 因为没有人用这个框架,所以不是很成熟
      • fb879d10f593:我觉得okhttp-utils就挺好的了
        fb879d10f593:@裸奔的凯子哥 1.在返回结果里面获取不到请求url...这个没有什么必要吧。。请求的url都是你传入的。。为什么要在结果里获取。。
        2.返回值我一般都是返回String,然后再去自己处理(没有感觉),感觉图片加载确实可有可无
        3.然后我大概看了下你的 demo 好像没有cookie的处理。。感觉这个还是很有必要的,web与原生混合开发的时候有用到
        裸奔的凯子哥:@Kuan 个人觉得有点过度封装了,造成了信息的丢失,对返回值的处理比较固定,不适合自定义处理的场景,另外感觉图片加载可有可无,不如直接去掉,本来想提交request,但是可能改动较大,不如直接另起炉灶单写了这个项目,当然这个项目肯定也有一些问题,欢迎提交issues
        裸奔的凯子哥:@Kuan 在返回结果里面获取不到请求url
      • ningso:叼叼的凯子:smile:
      • LostAbaddon:很抱歉,首页的文章的话,不能带有个人推广链接哟,所以,能不能去掉呢?
        LostAbaddon:@裸奔的凯子哥 CSDN的连接是否也可以去掉?
        个人博客与新浪微博的连接可以下载你个人介绍里的。

        PS:这个连接本身因为把后面的括号给带进去了所以实际上也打不开。。。
        裸奔的凯子哥:@塔塔酱 已更新
        裸奔的凯子哥:@塔塔酱 好的
      • alighters:中间的一部分代码显示有些问题。
        裸奔的凯子哥:@lighters_wei 已修正,多谢

      本文标题:开源项目OkHttpPlus——OkHttp封装库,支持GET、

      本文链接:https://www.haomeiwen.com/subject/ozirhttx.html