android kotlin開發(fā)中對網(wǎng)絡框架的封裝

? ? ?app項目的開發(fā)過程中,都少不了進行網(wǎng)絡請求的功能模塊慎菲。而現(xiàn)在的主流網(wǎng)絡框架中洽损,使用最多而且反饋最好. 最穩(wěn)定的就是 retrofit+okhttp+rxjava(rxandroid)的組合框架了失暴。今天記錄一下在kotlin語言開發(fā)下實現(xiàn)該網(wǎng)絡框架的封裝過程昂拂。

1.網(wǎng)絡請求原理

? ? ? ? 無論使用何種語言進行開發(fā)托慨,其實只是在語法的編寫和語法糖的調用上有一些差異嘁圈。但是需要明確的是魏身,先要搞清楚這一套網(wǎng)絡框架的原理肛炮,包括框架中每個模塊的具體作用止吐。

1.1 okhttp?

? ? okhttp是最常用的網(wǎng)絡請求框架了宝踪,最新的4.x的版本已經由java全部換成了kotlin,api的使用與老的3.x的版本也有了一些差異碍扔,具體調用可以去git官網(wǎng)查看瘩燥,先來看一張它的調用流程圖

調用流程

基本流程:

? ? 1.我們通過OkhttpClient創(chuàng)建一個Call,并發(fā)起同步或異步請求時不同;

????2.okhttp會通過Dispatcher對我們所有的RealCall(Call的具體實現(xiàn)類)進行統(tǒng)一管理颤芬,并通過execute()及enqueue()方法對同步或異步請求進行處理;

? ? 3.execute()及enqueue()這兩個方法會最終調用RealCall中的getResponseWithInterceptorChain()方法套鹅,從攔截器鏈中獲取返回結果;

? ?4.攔截器鏈中汰具,依次通過RetryAndFollowUpInterceptor(重定向攔截器)卓鹿、BridgeInterceptor(橋接攔截器)、CacheInterceptor(緩存攔截器)留荔、ConnectInterceptor(連接攔截器)吟孙、CallServerInterceptor(網(wǎng)絡攔截器)對請求依次處理,與服務的建立連接后聚蝶,獲取返回數(shù)據(jù)杰妓,再經過上述攔截器依次處理后,最后將結果返回給調用方碘勉。

? ? ?這其中不同的攔截器對應的不同的訪問情況巷挥,具體的介紹可以自行去官網(wǎng)了解,這里就不一一介紹了?验靡,而且okhttp的攔截器模式使得我們很容易添加一個自定義攔截器對請求和返回結果進行處理倍宾。

1.2 retrofit

? ? ? ? retrofit可以理解為在okhttp的基礎上進行加強再封裝的一個網(wǎng)絡框架,底層使用okhttp進行最終的訪問胜嗓,主要為了最大程度上優(yōu)化請求鏈接的參數(shù)構建和實現(xiàn)解耦高职,使用注解+java接口來定義后臺服務API接口。

注解主要分為 方法注解 和 參數(shù)注解

方法注解

@GET? ?表明HTTP請求方法為GET,(可選)注解的value屬性用來設置相對/絕對url

@POST? ?表明HTTP請求方法為POST,(可選)注解的value屬性用來設置相對/絕對url

@PUT? ? 表明HTTP請求方法為PUT,(可選)注解的value屬性用來設置相對/絕對url

@DELETE? ? 表明http請求方法為DELETE,(可選)注解的value屬性用來設置相對/絕對url

@PATCH? ?表明HTTP請求方法為PATCH,(可選)注解的value屬性用來設置相對/絕對url

@HEAD? ?表明HTTP請求方法為HEAD,(可選)注解的value屬性用來設置相對/絕對url

@OPTIONS? ?表明HTTP請求方法為OPTIONS,(可選)注解的value屬性用來設置相對/絕對url

@HTTP? 通過@HTTP注解指定http協(xié)議的請求方法,是否允許body,(可選)注解的value屬性用來設置相對/絕對url

@FormUrlEncoded? ?表明發(fā)起HTTP請求的RequestBody是form表單方式

@Multipart? ? 表明發(fā)起HTTP請求的RequestBody是Multipar方式

@Headers? ? 使用注解的value值數(shù)組作為HTTP請求的頭辞州,用于一些固定的Header參數(shù)

@Streaming? ? 用于需要直接返回流的函數(shù)

參數(shù)注解

@Url? ? HTTP請求的url路徑(相對/絕對),可以包含{path_holder},如:http://xxx.com/{user_holder}/detail

@Path? ?用于動態(tài)替換URL路徑中的path_holder

@Body? ?表明此參數(shù)用作HTTP請求的body

@Field? 表明此參數(shù)用作HTTP請求的form表單參數(shù)怔锌,key為注解的value值

@FieldMap? ?以map形式傳入的form表單參數(shù)

@Header? ?表明此參數(shù)用作HTTP請求的header,key為注解的value值

@HeaderMap? ?以map形式傳入的多個header鍵值對

@Part? ?表明參數(shù)為Http的multipart參數(shù)之一

@PartMap? 以map形式傳入的multipart參數(shù)表

@Query GET方法的query參數(shù)变过,用于拼接完整請求路徑

@QueryMap? ?以map傳入的GET方法的query參數(shù)埃元,用于拼接完整請求路徑

? ? ? 了解了注解之后,開始介紹Retrofit.create函數(shù)創(chuàng)建接口動態(tài)代理生成一個自定義的接口的實現(xiàn)類的過程

1 加載對應method的ServiceMethod實例

2 使用ServiceMethod實例和方法調用參數(shù)創(chuàng)建OkHttpCall

3 調用serviceMethod.callAdapter.adapt(okHttpCall)來產生method所定義的返回(Call<T>或者其他自定義CallAdapter支持的返回)

源碼1

這其中以下4個元素是比較重要的媚狰,也是retrofit功能強大的保證亚情,其中包括?callFactory,callAdapter哈雏,responseConverter 楞件,parameterHandlers?

? ??callFactory是用來創(chuàng)建真正要執(zhí)行的okhttp3.Call的工廠類衫生,可以Retrofit.Builder中設置,如果不設置土浸,默認會new一個OkHttpClient作為callFactory

callAdapter是用來最終處理OkHttpCall實例并返回接口Method所定義的返回

responseConverter 用來將Http請求的結果轉換成接口Method所定義的結果(return或者Callback<T>中的T)

parameterHandlers 根據(jù)接口Method參數(shù)的注解所生成的參數(shù)處理Handler數(shù)組

1.3? rxjava

? ? ? ? rxjava 其實是一個實現(xiàn)異步操作罪针,基于時間本身的第三方庫,沒有這個庫之前黄伊,我們執(zhí)行異步操作可以通過handler或者是tread進行泪酱,rajva等于就是針對這一類型事務處理的加強版本,那相對于傳統(tǒng)實現(xiàn)異步操作的功能还最,rxjava的好處或者是優(yōu)勢點在哪里呢墓阀?先來看看它的基本原理和使用。

? ? rxjava采用的是觀察者模式拓轻,有四個基本概念:Observable (可觀察者斯撮,即被觀察者)、 Observer (觀察者)扶叉、 subscribe (訂閱)勿锅、事件。Observable 和 Observer 通過 subscribe() 方法實現(xiàn)訂閱關系枣氧,從而 Observable 可以在需要的時候發(fā)出事件來通知 Observer溢十。

RxJava 的事件回調方法除了普通事件 onNext() (相當于 onClick() / onEvent())之外,還定義了兩個特殊的事件:onCompleted() 和 onError()达吞。

onCompleted(): 事件隊列完結张弛。RxJava 不僅把每個事件單獨處理,還會把它們看做一個隊列酪劫。RxJava 規(guī)定乌庶,當不會再有新的 onNext() 發(fā)出時,需要觸發(fā)

onCompleted() 方法作為標志契耿。

onError(): 事件隊列異常瞒大。在事件處理過程中出異常時,onError() 會被觸發(fā)搪桂,同時隊列自動終止透敌,不允許再有事件發(fā)出。

在一個正確運行的事件序列中, onCompleted() 和 onError() 有且只有一個踢械,并且是事件序列中的最后一個酗电。需要注意的是,onCompleted() 和 onError() 二者也是互斥的内列,即在隊列中調用了其中一個撵术,就不應該再調用另一個。

觀察者模式

????在 RxJava 的默認規(guī)則中话瞧,事件的發(fā)出和消費都是在同一個線程的嫩与。也就是說寝姿,如果只用上面的方法,實現(xiàn)出來的只是一個同步的觀察者模式划滋。觀察者模式本身的目的就是『后臺處理饵筑,前臺回調』的異步機制,因此異步對于 RxJava 是至關重要的处坪。而要實現(xiàn)異步根资,則需要用到 RxJava 的另一個線程切換概念: Scheduler ,在不指定線程的情況下同窘, RxJava 遵循的是線程不變的原則玄帕,即:在哪個線程調用 subscribe(),就在哪個線程生產事件想邦;在哪個線程生產事件裤纹,就在哪個線程消費事件。如果需要切換線程案狠,就需要用到 Scheduler (調度器)。RxJava 已經內置了幾個 Scheduler?

????Schedulers.newThread(): 總是啟用新線程钱雷,并在新線程執(zhí)行操作骂铁。

????Schedulers.io(): I/O 操作(讀寫文件、讀寫數(shù)據(jù)庫罩抗、網(wǎng)絡信息交互等)所使用的 Scheduler拉庵。行為模式和 newThread() 差不多,區(qū)別在于 io() 的內部實現(xiàn)是是用一個無數(shù)量上限的線程池套蒂,可以重用空閑的線程钞支,因此多數(shù)情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中操刀,可以避免創(chuàng)建不必要的線程烁挟。

????Schedulers.computation(): 計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算骨坑,即不會被 I/O 等操作限制性能的操作撼嗓,例如圖形的計算。這個 Scheduler 使用的固定的線程池欢唾,大小為 CPU 核數(shù)且警。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU礁遣。

? ? ?AndroidSchedulers.mainThread()斑芜,它指定的操作將在 Android 主線程運行

有了這幾個 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 兩個方法來對線程進行控制了祟霍。

subscribeOn(): 指定 subscribe() 所發(fā)生的線程杏头,即 Observable.OnSubscribe 被激活時所處的線程盈包。或者叫做事件產生的線程大州。

observeOn(): 指定 Subscriber 所運行在的線程续语。或者叫做事件消費的線程厦画。

? ?2 具體實現(xiàn)

? ? ? ?基本模塊的功能簡單的介紹完成了疮茄,現(xiàn)在我們開始組合它們,將它們分裝成通用的網(wǎng)絡請求模塊 根暑,首先我們需要在gradle文件中添加對應的遠程倉庫依賴力试。

依賴地址

? ? 代碼中首先實現(xiàn)okhttpclient請求類,常用的攔截器排嫌,連接時長等配置畸裳。

client類
請求日志的攔截器

? ?這樣最基本的一個ohttp模塊構建就完成了,接下來要開始進行retrofit模塊的處理淳地,既然是通用的請求模塊怖糊,那就需要使用泛型來實現(xiàn)統(tǒng)一的retrofit請求模塊的方法,其中包含有對應的gson解析工廠颇象,rxjava的適配器伍伤,設置最基本的okhttpclient模塊。

retrofit請求類

? ? 目前這一步遣钳,已經完成了網(wǎng)絡框架的大部分功能了扰魂,但是我們知道常規(guī)的網(wǎng)絡請求或者去數(shù)據(jù)時,為了保證app使用過程的流暢蕴茴,一般都是異步回調的操作劝评。,所以接下來要實現(xiàn)rxjava的相關功能倦淀。

rxjava觀察者模式

到了這一步蒋畜,很多人有疑問說沒見到具體的網(wǎng)絡請求包含在這里面。其實這正是rxjava的關鍵作用撞叽,它的主要作用只是設置觀察者和被觀察者百侧,進行事件的訂閱而已,我們最后看看具體事例使用能扒。

網(wǎng)絡請求1
retrofit接口類

這樣來看佣渴,就把rxjava和retrofit關聯(lián)在一起了,最終實現(xiàn)了異步回調的網(wǎng)絡請求. 代碼很簡單初斑,只是為了熟悉和掌握個功能的模塊及原理辛润,在此做個筆記記錄一下。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市砂竖,隨后出現(xiàn)的幾起案子真椿,更是在濱河造成了極大的恐慌,老刑警劉巖乎澄,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件突硝,死亡現(xiàn)場離奇詭異,居然都是意外死亡置济,警方通過查閱死者的電腦和手機解恰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浙于,“玉大人护盈,你說我怎么就攤上這事⌒咝铮” “怎么了腐宋?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長檀轨。 經常有香客問我胸竞,道長,這世上最難降的妖魔是什么参萄? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任卫枝,我火速辦了婚禮,結果婚禮上拧揽,老公的妹妹穿的比我還像新娘剃盾。我一直安慰自己腺占,他們只是感情好淤袜,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衰伯,像睡著了一般铡羡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上意鲸,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天烦周,我揣著相機與錄音,去河邊找鬼怎顾。 笑死读慎,一個胖子當著我的面吹牛,可吹牛的內容都是我干的槐雾。 我是一名探鬼主播夭委,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼募强!你這毒婦竟也來了株灸?” 一聲冷哼從身側響起崇摄,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慌烧,沒想到半個月后逐抑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡屹蚊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年厕氨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淑翼。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡腐巢,死狀恐怖,靈堂內的尸體忽然破棺而出玄括,到底是詐尸還是另有隱情冯丙,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布遭京,位于F島的核電站胃惜,受9級特大地震影響,放射性物質發(fā)生泄漏哪雕。R本人自食惡果不足惜船殉,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斯嚎。 院中可真熱鬧利虫,春花似錦、人聲如沸堡僻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钉疫。三九已至硼讽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間牲阁,已是汗流浹背固阁。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留城菊,地道東北人备燃。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像凌唬,于是被迫代替她去往敵國和親并齐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361