開源項(xiàng)目OkHttpPlus——OkHttp封裝庫(kù),支持GET、POST、UI線程回調(diào)、JSON格式解析、鏈?zhǔn)秸{(diào)用、小文件上傳下載及進(jìn)度監(jiān)聽

OkHttpPlus介紹

項(xiàng)目地址:https://github.com/ZhaoKaiQiang/OkHttpPlus

主要功能:OkHttp封裝,支持GET、POST、UI線程回調(diào)、JSON格式解析、鏈?zhǔn)秸{(diào)用、小文件上傳下載及進(jìn)度監(jiān)聽等功能

為什么要寫這么一個(gè)庫(kù)呢?

首先,是因?yàn)镺kHttp在4.4之后已經(jīng)作為底層的Http實(shí)現(xiàn)了,所以O(shè)kHttp這個(gè)庫(kù)很強(qiáng)大,值得我們學(xué)習(xí)。

其次,在我看來(lái),OkHttp使用起來(lái)不如Volley方便,OkHttp的回調(diào)都是在工作線程,所以如果在回調(diào)里面操作View的話,需要自己轉(zhuǎn)換到UI線程,非常繁瑣,所以需要封裝。也有將OkHttp作為Volley底層Http實(shí)現(xiàn)的用法,發(fā)送請(qǐng)求、維護(hù)請(qǐng)求隊(duì)列用的是Volley,實(shí)際的Http請(qǐng)求用的是OkHttp。

關(guān)于Volley和oOkHttp結(jié)合的Demo請(qǐng)戳煎蛋項(xiàng)目

如何使用

初始化

你可以在Application里面完成初始化,因?yàn)閷?duì)OkHttp的封裝主要使用的是代理設(shè)計(jì)模式,使用OkHttpProxy.getInstance()可以獲取到單例客戶端,你可以像沒(méi)封裝之前一樣,設(shè)置任意的參數(shù),比如下面就設(shè)置超時(shí)時(shí)間和忽略HTTPS認(rèn)證。

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方法

你大多數(shù)情況下是和OkHttpProxy這個(gè)代理類打交道,而且OkHttpPlus支持鏈?zhǔn)秸{(diào)用,內(nèi)部采用Builder設(shè)計(jì)模式,所以你可以像下面這樣使用

 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的構(gòu)造函數(shù)中,你需要傳入一個(gè)解析器,OkHttpPlus內(nèi)部支持5種解析器,這可以解決你大部分的需求

  • OkBaseParser,所有解析器的基類,不可直接使用
  • OkBaseJsonParser,所有JSON解析器的基類,你可以繼承它來(lái)定義自己的JSON解析
  • OkJsonParser,JSON解析器,支持JSONObject和JSONArray的解析,默認(rèn)使用GSON作為解析器
  • OkTextParser,String解析器,支持將結(jié)果以String方式輸出
  • OkFileParser,文件解析器,支持將結(jié)果保存為文件,你可以用來(lái)下載文件,但是不支持較大文件下載

所以如果你想獲取一個(gè)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數(shù)據(jù),你可以這樣

  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());
                    }
                });

當(dāng)然,如果你想自定義一個(gè)解析器,也是完全可以的。

OkHttpPlus的解析器部分使用的是策略設(shè)計(jì)模式,所以你可以像下面這樣自定義一個(gè)解析策略,完成結(jié)果的解析

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;
        }
    }
}

然后就可以將返回結(jié)果解析為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方法使用類似,你可以像下面這樣發(fā)送POST請(qǐng)求,并添加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());
                    }
                });

你可能注意到了,在發(fā)送每個(gè)請(qǐng)求的時(shí)候,我都調(diào)用了tag()方法,所以你可以在不需要的時(shí)候,將請(qǐng)求取消掉。

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

下載

你可以像下面這樣下載一個(gè)文件,但是由于下載的內(nèi)容都在內(nèi)存中,所以不支持大文件下載,否則會(huì)OOM

 String desFileDir = Environment.getExternalStorageDirectory().getAbsolutePath();
        OkHttpProxy.download(URL_DOWMLOAD, new DownloadListener(desFileDir, "json.jar") {

            @Override
            public void onUIProgress(Progress progress) {
                //當(dāng)下載資源長(zhǎng)度不可知時(shí),progress.getTotalBytes()為-1,此時(shí)不能顯示下載進(jìn)度
                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也支持小文件上傳,我這里測(cè)試使用的是七牛的上傳API,Token是有期限的,所以你需要在下面網(wǎng)址自己生成測(cè)試

 /**
     * 采用七牛上傳接口,Token有效期為12小時(shí),若Token無(wú)效,請(qǐng)?jiān)谙旅孀孕蝎@取
     * Token生成網(wǎng)址 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, "文件不存在,請(qǐng)修改文件路徑", 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());
                    }
                });
    }

靈感來(lái)源

本項(xiàng)目的靈感和部分代碼來(lái)自于下面兩個(gè)開源項(xiàng)目,謝謝他們的分享精神


尊重原創(chuàng),轉(zhuǎn)載請(qǐng)注明:From 凱子哥 侵權(quán)必究!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容