Android OkHttp 史上最優雅的設置baseUrl

前言

本文將在RxHttp的基礎上帶你們如何優雅的設置BaseUrl,若是您還未了解RxHttp,請移步php

RxHttp 一條鏈發送請求,新一代Http請求神器(一)java

RxHttp 一條鏈發送請求之強大的數據解析功能(二)git

RxHttp 一條鏈發送請求之強大的Param類(三)github

RxHttp 一條鏈發送請求之註解處理器 Generated API(四)app

爲什麼要重複造輪子

RxHttp一經推出,就有人問:難道Retrofit很差用嗎?爲啥還要本身去封裝呢?藉此文,跟你們簡單聊一聊。 爲何要重複造輪子?無非就一個緣由post

  • 之前的輪子有些功能很差用,用起來不夠優雅

Retrofit哪裏很差用,用起來不夠優雅?ui

首先,我以爲是對文件的操做不是那麼的友好,如文件上傳/下載、上傳/下載進度監聽、斷點下載,這些都須要咱們進行二次封裝,看過Android 史上最優雅的實現文件上傳、下載及進度的監聽的同窗知道,使用RxHttp是多麼的簡單;this

而後,是對多個baseUrl,或者說動態baseUrl不夠友好,Retrofit要求baseUrl 必須是一個final常量,咱們想要動態修改,就只能經過增長攔截器去實現,這也是本文重點要說的;url

最後,也是很是重要的一點,那就是Activity/Fragment銷燬時,對請求的關閉,一般咱們的作法是爲請求設置Tag,而後根據此Tag去關閉一系列請求,又或者拿到Call對象,去關閉單個請求,極其的麻煩,若是你使用RxHttp,在Activity/Fragment中,一行代碼就能搞定,而且支持在任意生命週期方法關閉請求,極其簡單高效。(注意:Retrofit結合RxJava,依然可以在RxJava中斷上下游時,調用Call對象的cancel方法,感謝評論區卓_修武大佬的指正)spa

以上就是我重複造輪子的主要緣由,歡迎你們交(Da)流(Lian)討論,下面將進入正題。

單個baseUrl

若是你的項目中只有一個BaseUrl,那麼只須要使用@DefaultDomain註解便可,以下:

public class Url {
    @DefaultDomain() //設置爲默認域名,對final關鍵字沒有要求
    public static String baseUrl = "http://ip.taobao.com/";
}
複製代碼

發送請求,咱們就能夠這樣

String url = "/service/getIpInfo.php";
  RxHttp.get(url) //Get請求
        .add("ip", "63.223.108.42") //添加參數
        .addHeader("accept", "*/*") //添加請求頭
        .addHeader("connection", "Keep-Alive")
        .addHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")
        .asString()  //這裏返回Observable<String> 對象
        //感知生命週期,並在主線程回調,Activity/fragment銷燬,自動關閉爲完成的請求
        .as(RxLife.asOnMain(this))
        .subscribe(s -> {
            //成功回調
        }, throwable -> {
            //失敗回調
        });
複製代碼

此時,發送請求前,RxHttp會對咱們傳入url作判斷,若是url裏已經有baseUrl,便是一條完成url連接,就不會添加@DefaultDomain註解代表的baseUrl,不然就會添加,咱們經過日誌來觀察如下結果(過濾RxHttp)

能夠看到,baseUrl跟url成功拼接在了一塊兒,並完成了請求。

注:註解@DefaultDomain只能使用一處,多處使用將編譯不經過

多個baseUrl

在上面代碼中,咱們只須要傳入一條完整的url連接,其實就已經實現了多個baseUrl的問題,而後,大部分開發者都喜歡將baseUrl 單獨寫在一個變量裏,若是每次發請求,咱們都須要以baseUrl+url的方式去實現,顯然不夠友好,那麼RxHttp又是若是去解決的呢?很簡單,使用@Domain註解,以下:

public class Url {
    @Domain(name = "Update")
    public static String update = "http://update.9158.com";

    @DefaultDomain() //設置爲默認域名,對final關鍵字沒有要求
    public static String baseUrl = "http://ip.taobao.com/";
}
複製代碼

此時rebuild一下項目,RxHttp類就會自動生成一個setDomainToUpdateIfAbsent()方法,此方法的命名規則爲setDomainTo+@Domain註解中指定的name字段的值+IfAbsent,見名思議,此方法是會在域名缺席的狀況下,添加咱們指定的域名,若是沒有指定,就會添加@DefaultDomain註解標記的默認域名。

此時發請求,咱們就能夠這樣:

String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
  RxHttp.get("/miaolive/Miaolive.apk")
        .setDomainToUpdateIfAbsent() //使用指定的域名
        .asDownload(destPath) //注意這裏使用DownloadParser解析器,並傳入本地路徑
        .as(RxLife.asOnMain(this))  //感知生命週期,並在主線程回調
        .subscribe(s -> {
            Log.d("RxHttp", "download success \npath=" + s);
            //下載成功,回調文件下載路徑
        }, throwable -> {
            //下載失敗
        });
複製代碼

咱們再經過日誌來觀察一下

能夠看到,baseUrl跟url成功拼接在了一塊兒,並完成了下載操做。

@Domain註解可使用多處,以下:

public class Url {
    @Domain(name = "Baidu")
    public static String update = "http://www.baidu.com";
    
    @Domain(name = "Hao123")
    public static String update = "https://www.hao123.com/";

    @Domain(name = "Update")
    public static String update = "http://update.9158.com";

    @DefaultDomain() //設置爲默認域名,對final關鍵字沒有要求
    public static String baseUrl = "http://ip.taobao.com/";
}
複製代碼

此時rebuild一下項目,RxHttp類下就會再新增setDomainToBaiduIfAbsent()setDomainToHao123IfAbsent()這兩個方法,故咱們發請求就能夠調用setDomainToXXXIfAbsent方法指定baseUrl。

動態baseUrl

某些狀況下,咱們的域名可能會被封,又或者其它緣由,致使咱們須要在app啓動的時候動態配置域名,若是你使用Retrofit的話,因爲Retrofit要求baseUrl必須是final常量,因此咱們就只能經過攔截器去實現,而RxHttp對baseUrl ,沒有final關鍵字的限制,咱們只須要對baseUrl從新賦值便可,並且,能夠在代碼中屢次賦值,賦值後當即生效。

如:咱們將baseUrl裏taobao域名改成baidu,改完當即發送請求。

Url.baseUrl = "http://www.baidu.com";  //更改域名,將taobao域名改成baidu
  RxHttp.get("/service/getIpInfo.php") //Get請求
        .add("ip", "63.223.108.42") //添加參數
        .addHeader("accept", "*/*") //添加請求頭
        .addHeader("connection", "Keep-Alive")
        .addHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")
        .asString()  //這裏返回Observable<Response> 對象
        .as(RxLife.asOnMain(this))  //感知生命週期,並在主線程回調
        .subscribe(s -> {
            //成功回調
        }, throwable -> {
            //失敗回調
        });
複製代碼

看一下日誌

能夠看到,域名成功被更改,並當即生效。因爲該接口不存在,因此返回了Html頁面代碼。

小結

怎麼樣,是否是最優雅的設置baseUrl?歡迎打臉。 其實,RxHttp遠不止本篇文章說的這些優勢,更多彩蛋,請查看源碼

本文的目的並不在於說Retrofit很差,而是提供一種新的思路與方案,供開發者去選擇。曾經有讀者問我,有沒有打算將RxHttp融入Retrofit,Retrofit的註解請求很好用,並且寫在一個類裏,很直觀。個人回答是 NO !RxHttp若是融入Retrofit,那RxHttp就是Retrofit,那還有什麼區別呢? 若是你喜歡將請求寫在一個類裏,RxHttp也是能實現的。以下:

public class Http {

    public static Observable<List<Student>> getStudents(int id, int page, int size) {
        return RxHttp.get("xxx/getStudent")
                .add("id", id).add("page", page).add("size", size)
                .asList(Student.class);
        //後期會增長add(key,value,key,value....)可變參數方法
    }
    
    //其它請求同理
}
複製代碼

藉此機會,若是你對RxHttp感興趣,又有本身的想法,歡迎你加入維護的隊伍中。

好了,轉載請註明出處,🙏🙏🙏。

最後,歡迎你們,加羣溝通交流 RxHttp&RxLife 交流羣: 378530627,以前忘記建羣了😅😅,但願你們能多給點建議,我會第一時間回覆。🙏🙏🙏

若是你以爲RxHttp好用,請記得給我star。萬分感謝🙏🙏🙏

相關文章
相關標籤/搜索