開源項目OkHttpPlus——支持GET、POST、UI線程回調、JSON格式解析、鏈式調用、文件上傳下載

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了

  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 凱子哥(http://blog.csdn.net/zhaokaiqiang1992) 侵權必究!

關注我的微博,可以獲得更多精彩內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章