解決Retrofit多BaseUrl及執行時動態改變BaseUrl(二)

JessYan發表於2018-07-09

原文地址: https://www.jianshu.com/p/35a8959c2f86

前言

我在之前的文章 《解決Retrofit多BaseUrl及執行時動態改變BaseUrl》 中,介紹了市面上能夠解決此類問題的 4 個常見的解決方案,並開源了自己經過優化後的解決方案 RetrofitUrlManager,現在再為大家帶來此係列的第二篇文章,這篇文章主要介紹 RetrofitUrlManager 針對 BaseUrl 替換邏輯的重大升級,因為這個升級對於 RetrofitUrlManager 足夠重要,將使 RetrofitUrlManager 能夠從容應對更多複雜的需求,所以單獨寫一篇文章讓更多的人能夠知道

Github : 您的 Star 是我堅持的動力 ✊

為什麼不使用多 Retrofit 例項的方案?

在上篇文章 《解決Retrofit多BaseUrl及執行時動態改變BaseUrl》 中,4 種方案的特點和不足我都描述的很清楚,建議沒看過這篇文章的可以去看看這篇文章,擴寬知識面,在後面的時間裡經常有人問我為什麼不使用多 Retrofit 例項的方案,多個 Retrofit 例項看起來並不會佔用多少資源啊?

在回答之前為了讓看這篇文章的人能瞭解我在說什麼,所以我再貼上下 上篇文章 中關於這個方案的部分描述

民間常用解決方案:
之前也看過很多開源的聚合類 App 原始碼, 像一些整合 知乎、 豆瓣、 Gank 等多個平臺資料的 App, 因為各自平臺的域名不同, 所以大多數這類 App 會給每個平臺都各自建立一個 Retrofit 物件, 即不同的 BaseUrl 使用不同的 Retrofit 物件來建立 ApiService 進行請求, 這樣只要新增一個不同的 BaseUrl, 那就需要重新建立一個新的 Retrofit 物件

我在這篇文章中重新回答下這個問題,為每個不同的 BaseUrl 都建立一個其他配置屬性都一模一樣的 Retrofit 例項不止會造成資源的浪費,還會造成介面管理成本的增加,這個才是最重要的一點, 舉個例

我們平時專案中所有的 ApiService 都是使用同一個 Retrofit 例項的 Retrofit#create(ApiService) 方法進行例項化後開始介面的請求

但是當專案中出現多個 Retrofit 例項後,我們在開發中不光要區分哪些介面使用哪個 ApiService,還要區分哪些 ApiService 需要使用哪個 Retrofit 例項進行例項化,如果 ApiService 使用錯誤的 Retrofit 例項進行例項化,那這個 ApiService 的所有介面請求都註定完全失敗

越複雜的專案,開發人數越多的專案,出錯的風險就越大,並且擴充套件性也在大打折扣,後面一有變更將會十分痛苦,隨著專案中介面的增加,以及 Retrofit 例項的增加 (BaseUrl 的增加),這個管理成本會成幾何倍的增加

使用多 Retrofit 例項的方案前期投入成本過高,可能會影響之前專案管理介面的方式,某些封裝過 Retrofit 的專案,也可能需要大改,對於老專案的接入不利,而使用 RetrofitUrlManager 不僅可以滿足多 BaseUrl 及執行時動態改變 BaseUrl 的需求,還具有熱插拔以及低侵入性的特點,在使用過程中將不會影響到之前的介面管理方式和使用方式,還具有極強的擴充套件性,可應對後面陸續增加的極其複雜的 BaseUrl 替換需求

升級之前的 RetrofitUrlManager 的問題

此次升級之前的 RetrofitUrlManager 版本,只是將 上篇文章 的思想完全實現,有了整個框架的基礎,但是在動態替換 BaseUrl 方面還不夠強大,最被大家吐槽的就是隻能替換 BaseUrl 的域名

比如一個需要替換 BaseUrlUrl 地址為 "https:www.google.com/api/v2",其中 "https:www.google.com/api" 是我們傳給 RetrofitBaseUrl,這時我們使用 RetrofitUrlManager 框架,想把 BaseUrl 替換成 "https:www.github.com",我們期望的替換後的 URL 地址是 "https:www.github.com/v2",但使用框架替換後的實際 URL 地址是 "https:www.github.com/api/v2", "/api" 作為 BaseUrl 的一部分並沒有被新的 BaseUrl 替換掉,只是替換了 BaseUrl 中的域名

RetrofitUrlManager 是如何改善的

改善之前先要先分析為什麼會這樣?因為 RetrofitUrlManager 框架在攔截器中攔截到的 URL 地址是 Retrofit 已經把 BaseUrl 和介面註解中的相對路徑合併後得到的最終路徑地址,所以框架並不知道您傳給 RetrofitBaseUrl 除了域名外還包含後面的 "/api",框架不知道 BaseUrl 的具體值,所以框架只會預設所有的 BaseUrl 都只含有域名,所以也就只能替換域名

高階模式

想要解決此類問題也很簡單,告訴 RetrofitUrlManager 框架您傳給 RetrofitBaseUrl 具體值即可,所以框架升級後增加了 RetrofitUrlManager#startAdvancedModel(String) 方法,在 App 初始化時將您傳給 RetrofitBaseUrl 同樣傳給此方法,即可開啟高階模式,高階模式即可替換擁有多個 pathSegmentsBaseUrl,不再侷限於只能替換域名

什麼是 pathSegment?

"https://www.github.com/wiki/part?name=jess" 中,其中的 "/wiki""/part" 就是 pathSegment, PathSize 就是 pathSegment 的個數

這個 URL 地址的 PathSize 就是 2, 第一個 pathSegment"/wiki",第二個 pathSegment"/part",可以粗略的理解為域名後面跟了幾個 "/" PathSize 就是幾

高階模式的替換規則

  1. URL 地址為 "https://www.github.com/wiki/part",您在 App 初始化時傳入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com/wiki",您想替換成的 BaseUrl 地址是 "https://www.google.com/api",經過框架替換後生成的最終 URL 地址為 "http://www.google.com/api/part"

  2. URL 地址為 "https://www.github.com/wiki/part",您在 App 初始化時傳入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com/wiki",您想替換成的 BaseUrl 地址是 "https://www.google.com",經過框架替換後生成的最終 URL 地址為 "http://www.google.com/part"

  3. URL 地址為 "https://www.github.com/wiki/part", 您在 App 初始化時傳入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com",您想替換成的 BaseUrl 地址是 "https://www.google.com/api",經過框架替換後生成的最終 URL 地址為 "http://www.google.com/api/wiki/part"

超級模式

超級模式是高階模式的加強版,優先順序高於高階模式,按理說高階模式就能滿足開發中的大部分需求,那什麼又是超級模式呢?那就要先來說說高階模式了

高階模式的原理

在高階模式中您需要在 App 初始化時將您傳給 RetrofitBaseUrl 同樣傳給 RetrofitUrlManager#startAdvancedModel(String) 一份,用以開啟高階模式,成功開啟高階模式後,這個傳給 RetrofitUrlManager#startAdvancedModel(String)BaseUrl 就會作為框架替換 BaseUrl 的基準

什麼叫作基準呢? 用此 BaseUrl 開啟高階模式,並不意味著框架就只能替換 域名"www.github.com" 前兩個 pathSegments"/wiki/part"URL,只要擁有域名以及大於或等於兩個 pathSegmentsURL 都可以被框架替換,因此高階模式只會儲存傳入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl 的格式 (儲存 pathSegments 的個數),並不是儲存具體的值

高階模式的侷限

如果傳給 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com/wiki/part" (PathSize = 2),框架就會將專案中所有 URL 中的 域名 以及 域名 後面的前兩個 pathSegments 作為可被替換的 BaseUrl 整體,意味著框架只會將 URL 中的 域名 以及前兩個 pathSegments 剪下並替換為您期望的 BaseUrl

這時伺服器突然作出調整,專案中的一部分 URL 只需要將 "https://www.github.com/wiki" (PathSize = 1) 替換掉, 第二個 pathSegment "/part" 不再作為 BaseUrl 的一部分,不能被替換掉,必須要保留下來

這時專案中就出現了多個需要被替換的 BaseUrl 格式 (PathSize 不同),有些 URL 只需要替換 域名 以及前兩個 pathSegments,有些又只需要替換 域名 以及前一個 pathSegments,但是在開啟高階模式時,只儲存了一個 BaseUrl 的格式,這時使用高階模式實現此需求就比較棘手

這個需求是一個比較變態的需求,可能很多人遇不上,但是我想讓您知道當您遇上了也不要怕,因為 RetrofitUrlManager 的超級模式已經幫您考慮周全

超級模式的用法

超級模式與高階模式不同的是,開啟超級模式並不需要呼叫 API,只須要在需要開啟超級模式的 Url 尾部加上 RetrofitUrlManager#IDENTIFICATION_PATH_SIZE (#baseurl_path_size=) + PathSize,這樣就明確的告訴了框架,在這個 URL 中需要被替換的 BaseUrl 含有幾個 pathSegments,相當於每個 URL 都可以指定自己需要被替換的 BaseUrl 的格式,這樣就比高階模式只能在 App 初始化時,指定一個全域性的 BaseUrl 格式靈活得多,如果當您開啟高階模式的同時也開啟了超級模式,由於超級模式的優先順序高於高階模式,所以只會執行超級模式

超級模式的替換規則

  1. URL 地址為 "https://www.github.com/wiki/part#baseurl_path_size=1""#baseurl_path_size=1" 表示其中 BaseUrl"https://www.github.com/wiki",您想替換成的 BaseUrl 地址是 "https://www.google.com/api",經過框架替換後生成的最終 URL 地址為 "http://www.google.com/api/part"

  2. URL 地址為 "https://www.github.com/wiki/part#baseurl_path_size=1""#baseurl_path_size=1" 表示其中 BaseUrl"https://www.github.com/wiki",您想替換成的 BaseUrl 地址是 "https://www.google.com",經過框架替換後生成的最終 URL 地址為 "http://www.google.com/part"

  3. URL 地址為 "https://www.github.com/wiki/part#baseurl_path_size=0""#baseurl_path_size=0" 表示其中 BaseUrl"https://www.github.com",您想替換成的 BaseUrl 地址是 "https://www.google.com/api",經過框架替換後生成的最終 URL 地址為 "http://www.google.com/api/wiki/part"

  4. URL 地址為 "https://www.github.com/wiki/part/issues/1#baseurl_path_size=3""#baseurl_path_size=3" 表示其中 BaseUrl"https://www.github.com/wiki/part/issues",您想替換成的 BaseUrl 地址是 "https://www.google.com/api",經過框架替換後生成的最終 URL 地址為 "http://www.google.com/api/1"

三種模式比較

在升級之前,框架就只有一個預設的普通模式 (只能替換域名),在升級之後新增了 高階模式超級模式,這兩個模式讓框架變得更加強大,在上面的內容中也詳細的介紹了這兩個模式,現在就來總結下這三個模式,讓大家能夠按照自己的需求選擇出最適合的模式

替換 BaseUrl 的自由程度 (可擴充套件性)

普通模式 < 高階模式 < 超級模式

  • 普通模式: 只能替換域名

  • 高階模式: 只能替換在 RetrofitUrlManager#startAdvancedModel(String) 中傳入的固定 BaseUrl 格式

  • 超級模式: 每個 URL 都可以隨意指定可被替換的 BaseUrl 格式

使用上的複雜程度

普通模式 < 高階模式 < 超級模式

  • 普通模式: 無需做過多配置

  • 高階模式: 在 App 初始化時呼叫一次 RetrofitUrlManager#startAdvancedModel(String) 即可

  • 超級模式: 每個需要開啟超級模式的 URL 尾部都需要加入 RetrofitUrlManager#IDENTIFICATION_PATH_SIZE (#baseurl_path_size=) + PathSize

總結

由此可見,自由度越強,使用上也越複雜,所以可以根據自己的需求選擇對應的模式,並且也可以根據需求的變化隨意升級或降級這三種模式

這次更新讓 RetrofitUrlManager 的能力提升了一個檔次,足以應對各種複雜的 BaseUrl 替換需求,正因為 RetrofitUrlManager 極強的擴充套件性,現在甚至可以做到,讓伺服器可以通過遠端動態控制專案中的多個 BaseUrl

如果還有什麼問題或者需求可以給我提 Issues,如果 RetrofitUrlManager 能夠給您帶來實質的幫助,也請不要吝嗇您的 Star

公眾號

掃碼關注我的公眾號 JessYan,一起學習進步,如果框架有更新,我也會在公眾號上第一時間通知大家

解決Retrofit多BaseUrl及執行時動態改變BaseUrl(二)


Hello 我叫 JessYan,如果您喜歡我的文章,可以在以下平臺關注我

-- The end

相關文章