日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[转]RxHttp 一条链发送请求,新一代Http请求神器(一)

發布時間:2023/12/4 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转]RxHttp 一条链发送请求,新一代Http请求神器(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

簡介

?

RxHttp是基于OkHttp的二次封裝,并于RxJava做到無縫銜接,一條鏈就能發送一個完整的請求。主要功能如下:

?

  • 支持Get、Post、Put、Delete等任意請求方式,可自定義請求方式
  • 支持Json、DOM等任意數據解析方式,可自定義數據解析器
  • 支持文件下載/上傳,及進度的監聽,并且支持斷點下載
  • 支持在Activity/Fragment的任意生命周期方法,自動關閉未完成的請求
  • 支持添加公共參數/頭部信息,且可動態更改baseUrl
  • 支持請求串行和并行

?

gradle依賴

?

implementation 'com.rxjava.rxhttp:rxhttp:1.0.4' //注解處理器,生成RxHttp類,即可一條鏈發送請求 annotationProcessor 'com.rxjava.rxhttp:rxhttp-compiler:1.0.4' //管理RxJava及生命周期,Activity/Fragment 銷毀,自動關閉未完成的請求 implementation 'com.rxjava.rxlife:rxlife:1.0.4'

?

RxHttp 源碼
RxLife 源碼

?

初始化

?

//設置debug模式,此模式下有日志打印 HttpSender.setDebug(boolean debug) //非必須,只能初始化一次,第二次將拋出異常 HttpSender.init(OkHttpClient okHttpClient) //或者,調試模式下會有日志輸出 HttpSender.init(OkHttpClient okHttpClient, boolean debug)

?

此步驟是非必須的,不初始化或者傳入null即代表使用默認OkHttpClient對象。

?

疑問:標題不是說好的是RxHttp,這么用HttpSender做一些初始化呢?這里先賣一個關子,后面會解答

?

添加公共參數/頭部及重新設置url

?

相信大多數開發者在開發中,都遇到要為Http請求添加公共參數/請求頭,甚至要為不同類型的請求添加不同的公共參數/請求頭,為此,RxHttp為大家提供了一個靜態接口回調,如下,每發起一次請求,此接口就會被回調一次,并且此回調在子線程進行(在請求執行線程回調)

?

HttpSender.setOnParamAssembly(new Function() {@Overridepublic Param apply(Param p) { if (p instanceof GetRequest) {//根據不同請求添加不同參數} else if (p instanceof PostRequest) {} else if (p instanceof PutRequest) {} else if (p instanceof DeleteRequest) {}//可以通過 p.getSimpleUrl() 拿到url更改后,重新設置//p.setUrl("");return p.add("versionName", "1.0.0")//添加公共參數.addHeader("deviceType", "android"); //添加公共請求頭} });

?

然后有些請求我們不希望添加公共參數/請求頭,RxHttp又改如何實現呢?很簡單,發起請求前,設置不添加公共參數,如下:

?

Param param = Param.get("http://...")//設置是否對Param對象修飾,即是否添加公共參數,默認為true.setAssemblyEnabled(false); //設為false,就不會回調上面的靜態接口

?

到這,也許你們會有疑問,Param 是什么東東,下面就為大家講解。

?

Param

?

首先,我們來看看如何發送一個請求

?

Param param = Param.get("http://...").add("key", "value"); Disposable disposable = HttpSender.from(param).subscribe(s -> { //這里的s為String類型,即Http請求的返回結果//成功回調}, throwable -> {//失敗回調});

?

疑問:說好的一條鏈發送請求呢?別著急,還沒到放大招的時候
到這,我可以告訴大家,Param承擔的是一個請求體的一個角色,我們通過Param可以確定請求方式(如:Get、Post、Put、Delete等請求方式)、添加請求參數、添加請求頭、添加File對象等;然后通過HttpSender,傳入Param對象,將請求發送出去。

?

HttpSender

?

到這,有人又有疑問,前面初始化、設置公共參數都用到了HttpSender,這里發送請求又用到了HttpSender ,那么它又是承擔怎么樣的一個角色呢?看名字,我們可以理解為它就是一個請求發送者,通過一個from操作符,傳入一個Param對象,然后返回一個RxJava的Observable對象,此時,我們就可以使用RxJava強大的操作符去處理相關的邏輯(這就是簡介說的,做到了與RxJava的無縫鏈接),在這,我們只是使用了subscribe操作符去訂閱觀察者。

?

RxHttp

?

現在,我們正式放大招,標題說好的一條鏈發送請求,既然吹牛了,就要去實現它。拿上面的例子,看看我們如何一條鏈實現,上代碼

?

RxHttp.get("http://...").add("key", "value").from() .subscribe(s -> { //這里的s為String類型,即Http請求的返回結果//成功回調}, throwable -> {//失敗回調});

?

我們的主角RxHttp終于登場了,可以看到使用RxHttp類我們就實現了一條鏈完成請求的發送,那它又是承擔一個什么角色呢?我們暫時可以理解為RxHttp=Param+HttpSender,并且還有自己特殊的使命。至于什么使用,后面會講解。

?

我們現在來解疑惑,為什么我們的庫叫RxHttp,但是初始化、設置公共參數等卻用HttpSender?因為RxHttp這個類不在RxHttp庫中,它是通過注解處理器生成的類。前面我們看到gradle依賴時,使用了

?

annotationProcessor 'com.rxjava.rxhttp:rxhttp-compiler:1.0.2'

?

該注解處理器的目的就是在項目中生成RxHttp類,那為何不直接把它寫到庫里面去呢?前面講過,因為它有自己的使命,而這個使命,就是我們可以通過注解,在RxHttp中生成自定義的api,我們來看看如何使用注解。

?

動態設置baseUrl

?

現實開發中,大部人開發者都會將baseUrl 單獨抽取出來,RxHttp也考慮到了這一點,RxHttp通過@DefaultDomain注解來配置baseUrl,看代碼

?

public class Url {@DefaultDomain() //設置為默認域名public static String baseUrl = "http://ip.taobao.com/"; }

?

rebuild一下項目,此時我們發送請求就可以直接傳入path路徑,如下:

?

RxHttp.get("/service/getIpInfo.php").add("key", "value").from() .subscribe(s -> { //這里的s為String類型,即Http請求的返回結果//成功回調}, throwable -> {//失敗回調});

?

RxHttp在發送請求前,會對url做判斷,如果沒有域名,就會自定加上默認的域名,也就是baseUrl。然后,如果我們不想使用默認的域名呢?RxHttp也考慮到來,提供了一個@Domain注解,我們再來看看用法:

?

public class Url {@Domain(name = "Update9158") //設置非默認域名,name 可不傳,不傳默認為變量的名稱public static String update = "http://update.9158.com";@DefaultDomain() //設置為默認域名public static String baseUrl = "http://ip.taobao.com/"; }

?

此時再rebuild一下項目,就會在RxHttp類中生成一個setDomainToUpdate9158IfAbsent()方法,其中的Update9158字符就是name指定的名字,然后發請求就可以這樣:

?

RxHttp.get("/service/getIpInfo.php").setDomainToUpdate9158IfAbsent().add("key", "value").from() .subscribe(s -> { //這里的s為String類型,即Http請求的返回結果//成功回調}, throwable -> {//失敗回調});

?

此時,RxHttp檢測到url已經配置了域名,就不會再去使用默認的域名。同樣的,setDomainToUpdate9158IfAbsent也會檢測url 有沒有配置域名,如果配置了,也不會使用我們指定的域名。

?

注意:@Domain注解可以在多個地方使用,而@DefaultDomain()只能在一個地方使用,否則編譯不通過,很好理解,默認域名只可能有一個。兩個注解都要使用在public static修飾的String類型變量上,對final關鍵字沒有要求,可寫可不寫,這就表明,baseUrl 可以動態更改,RxHttp始終會拿到的最新的baseUrl 。怎么樣,是不是很nice!!
更多注解使用請查看RxHttp 擴展篇之注解處理器 Generated API(八)

?

接下來,我們來看看,如何發送Post請求、如何在Activity/Fragment銷毀時,自動關閉為完成的請求、如何上傳/下載文件及進度的監聽、如何把Http返回的結果自動解析成我們想要的對象。

?

注:以下講解均使用RxHttp

?

Post

?

RxHttp.postForm("http://...").add("key", "value").from() .subscribe(s -> { //這里的s為String類型,即Http請求的返回結果//成功回調}, throwable -> {//失敗回調});

?

可以看到,跟上面的Get請求只有一點不同,Get是RxHttp.get,而Post是RxHttp.postForm,除此之外,沒有任何區別,我們在看來來,RxHttp都有哪些靜態方法供我們選擇請求方式
可以看到,默認提供了10個靜態方法供我們選擇具體的請求方式,有Get、Post、Put等,而Post等又分為postForm和postJson,這個好理解,前者是發送表單形式的post請求,后者是發送json字符串的post請求。

?

現實中,這些默認的請求方式顯然不能滿足我們的需求,如:我要發送加密的post請求,這個時候該怎么辦呢?此時就需要我們自定義請求方式。自定義請求方式請查看RxHttp 擴展篇之Param擴展(七)

?

Activity 銷毀,自動關閉未完成的請求

?

上面的案例中,在Activity/Fragment銷毀時,如果請求還未完成,就會造成Activity/Fragment 無法回收,導致內存泄漏。這是非常嚴重的問題,那么RxHttp是如何解決的呢?此時,就要引入我自己寫的另一個庫RxLife,直接看看如何使用

?

RxHttp.postForm("http://...").add("key", "value").from().as(RxLife.as(this)) //訂閱觀察者前,加上這句話即可.subscribe(s -> {//成功回調}, throwable -> {//失敗回調});//或者RxHttp.postForm("http://...").add("key", "value").from().as(RxLife.asOnMain(this)) //asOnMain 可以在主線程回調觀察者.subscribe(s -> {//成功回調}, throwable -> {//失敗回調});

?

這里的this為LifecycleOwner對象,它是一個接口,這里我們傳入的是Activity,因為Activity實現了LifecycleOwner接口。當Activity/Fragment銷毀時,會將RxJava的管道中斷,管道中斷時,又會將未完成的請求自動關閉。
對RxLife不了解的同學請查看Android RxLife 一款輕量級別的RxJava生命周期管理庫 (一),這里不詳細講解。在下面的講解中,我們均會使用RxLife

?

文件上傳/下載及進度監聽

?

使用RxHttp,可以很優雅的實現文件上傳/下載及進度的監聽,如何優雅?直接上代碼

?

文件上傳

?

RxHttp.postForm("http://...") //發送Form表單形式的Post請求.add("key", "value").add("file1", new File("xxx/1.png")) //添加file對象.add("file2", new File("xxx/2.png")).from() //from操作符,是異步操作.as(RxLife.asOnMain(this)) //感知生命周期,并在主線程回調.subscribe(s -> { //成功回調}, throwable -> {//失敗回調});

?

可以看到,文件上傳跟普通的post請求其實沒啥區別,無非就是在post請求的基礎上,調用add方法添加要上傳的文件對象。

?

文件下載

?

//文件存儲路徑String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk").download(destPath) //注意這里使用download操作符,并傳入本地路徑.as(RxLife.asOnMain(this)) //感知生命周期,并在主線程回調.subscribe(s -> {//下載成功,回調文件下載路徑}, throwable -> {//下載失敗});

?

下載跟普通請求不同的是,下載使用的是download操作符,其它都一樣。

?

文件下載進度監聽

?

//文件存儲路徑String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk").downloadProgress(destPath) //注:如果需要監聽下載進度,使用downloadProgress操作符.observeOn(AndroidSchedulers.mainThread()).doOnNext(progress -> {//下載進度回調,0-100,僅在進度有更新時才會回調,最多回調101次,最后一次回調文件存儲路徑int currentProgress = progress.getProgress(); //當前進度 0-100long currentSize = progress.getCurrentSize(); //當前已下載的字節大小long totalSize = progress.getTotalSize(); //要下載的總字節大小String filePath = progress.getResult(); //文件存儲路徑,最后一次回調才有內容}).filter(Progress::isCompleted)//下載完成,才繼續往下走.map(Progress::getResult) //到這,說明下載完成,返回下載目標路徑.as(RxLife.as(this)) //感知生命周期.subscribe(s -> {//s為String類型,這里為文件存儲路徑//下載完成,處理相關邏輯}, throwable -> {//下載失敗,處理相關邏輯});

?

下載進度的監聽我們稍微看一下 ,首先一點,下載使用download操作符,而下載進度監聽使用downloadProgress操作符,隨后,我們使用了doOnNext操作符處理進度回調,注意這里是僅當有進度更新時,才會回調,其中的progress變量是一個Progress類型的對象,我們貼上源碼:

?

public class Progress<T> {private int progress; //當前進度 0-100private long currentSize;//當前已完成的字節大小private long totalSize; //總字節大小private T mResult; //http返回結果,上傳/下載完成時調用//省略get/set方法 }

?

由于進度回調會執行101次(上面注釋有解釋),而最下面觀察者其實是不需要關心這么多事件的,只需要關心最后下載完成的事件,所以使用了filter操作符過濾事件,只要還未下載完成,就將事件過濾調,不讓往下走。最終下載完成后,拿到本地下載路徑。

?

文件上傳進度監聽

?

RxHttp.postForm("http://www.......") //發送Form表單形式的Post請求.add("file1", new File("xxx/1.png")).add("file2", new File("xxx/2.png")).add("key1", "value1")//添加參數,非必須.add("key2", "value2")//添加參數,非必須.addHeader("versionCode", "100") //添加請求頭,非必須.uploadProgress() //注:如果需要監聽上傳進度,使用uploadProgress操作符.observeOn(AndroidSchedulers.mainThread()) //主線程回調.doOnNext(progress -> {//上傳進度回調,0-100,僅在進度有更新時才會回調,最多回調101次,最后一次回調Http執行結果int currentProgress = progress.getProgress(); //當前進度 0-100long currentSize = progress.getCurrentSize(); //當前已上傳的字節大小long totalSize = progress.getTotalSize(); //要上傳的總字節大小String result = progress.getResult(); //Http執行結果,最后一次回調才有內容}).filter(Progress::isCompleted)//過濾事件,上傳完成,才繼續往下走.map(Progress::getResult) //到這,說明上傳完成,拿到Http返回結果并繼續往下走.as(RxLife.as(this)) //感知生命周期.subscribe(s -> { //s為String類型,由SimpleParser類里面的泛型決定的//上傳成功,處理相關邏輯}, throwable -> {//上傳失敗,處理相關邏輯});

?

上傳進度監聽使用downloadProgress操作符,剩下的操作跟下載進度監聽的操作都一樣,通過doOnNext監聽上傳進度,然后過濾事件,最終拿到Http的返回結果。

?

數據解析器Parser

?

在上面的案例中,觀察者拿到數據類型都是String類型,然后現實開發中,我們經常需要對數據解析成我們想要的對象,RxHttp考慮到了這一點,現在我們就來看看如何的到我們想要的對象

?

我們拿淘寶獲取IP的接口作為測試接口http://ip.taobao.com/service/getIpInfo.php?ip=63.223.108.42
對應的數據結構如下

?

public class Response {private int code;private Address data;//省略set、get方法class Address {//為簡單起見,省略了部分字段private String country; //國家private String region; //地區private String city; //城市//省略set、get方法} }

?

開始發送請求

?

RxHttp.get("http://ip.taobao.com/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)").fromSimpleParser(Response.class) //這里返回Observable<Response> 對象.as(RxLife.asOnMain(this)) //感知生命周期,并在主線程回調.subscribe(response -> {//成功回調}, throwable -> {//失敗回調});

?

可以看到,這里我們沒有用from操作符,而是用了fromSimpleParser操作符,并且傳入Response.class,最后觀察者拿到的response變量就是Response類型的對象。怎么樣,是不是很簡單。RxHttp為我們提供了一系列的fromXXX方法,我們來看一下:

我們可以看到,一些基本類型的封裝對象RxHttp都為我們封裝好了,還有一個fromListParser方法,此方法是用來解析集合對象的,一些常見的數據結構,RxHttp都為我們考慮到了,并封裝好了,然后,一些不常見的數據呢?眼尖的你也許發現了,上圖中還有一個<T> Observable<T> from(Parser<T> parser)方法,它允許我們傳入一個自定義的解析器,更多解析器的介紹,請查看RxHttp 之強大的數據解析功能(二)

?

最后,附上RxHttp一些常用的用法,如下:

?

RxHttp.postForm("/service/getIpInfo.php") //發送Form表單形式的Post請求.setDomainToUpdate9158IfAbsent() //手動設置域名,此方法是通過@Domain注解生成的.tag("RxHttp.get") //為單個請求設置tag.setUrl("http://...") //重新設置url.setAssemblyEnabled(false) //設置是否添加公共參數,默認為true.cacheControl(CacheControl.FORCE_NETWORK) //緩存控制.setParam(Param.postForm("http://...")) //重新設置一個Param對象.add(new HashMap<>()) //通過Map添加參數.add("int", 1) //添加int類型參數.add("float", 1.28838F) //添加float類型參數.add("double", 1.28838) //添加double類型參數.add("key1", "value1") //添加String類型參數.add("key2", "value2", false) //根據最后的boolean字段判斷是否添加參數 .add("file1", new File("xxx/1.png")) //添加文件對象.addHeader("headerKey1", "headerValue1") //添加頭部信息.addHeader("headerKey2", "headerValue2", false)//根據最后的boolean字段判斷是否添加頭部信息 .fromSimpleParser(String.class) //這里返回Observable<T> 對象 fromXXX都是異步操作符//感知生命周期,并在主線程回調,當Activity/Fragment銷毀時,自動關閉未完成的請求.as(RxLife.asOnMain(this)) .subscribe(s -> { //訂閱觀察者//成功回調}, throwable -> {//失敗回調});

?

小結

?

到這,RxHttp的基本用法我們就講解完畢了,可以看到,使用RxHttp類一條鏈就能完成一個完整的Http請求,簡單一點,就是請求三部曲:

?

  • 首先,確定請求方式并添加相關參數
  • 然后,確定解析器,指定要解析成的類型
  • 最后,訂閱觀察者,開始發送請求

?

以上所有的案例都離不開這3個步驟。最后,你會發現,RxHttp除了提供的一系列強大的功能外,在寫法上,不管什么請求,都極其的相似,只要通過RxHttp類,就能一條鏈,完成所有的請求,極大的降低了學習成本。

?

注:要想在項目中生成RxHttp類,至少需要使用一次注解類,否則檢測不到注解,就無法生成。

?

如果你覺得RxHttp+RxLife好用,請記得給我star
如果有好的idea,請留言或者聯系我。

?

更過詳情請查看RxHttp系列其它文章

?

RxHttp 之強大的數據解析功能(二)

?

RxHttp 介紹篇之Param介紹(三)

?

RxHttp 介紹篇之多請求串行與并行(四)

?

RxHttp 擴展篇之Param擴展(六)

?

RxHttp 擴展篇之注解處理器 Generated API(七)


---------------------
作者:劉敬興
來源:CSDN
原文:https://blog.csdn.net/liujingxing93/article/details/86600477
版權聲明:本文為作者原創文章,轉載請附上博文鏈接!

總結

以上是生活随笔為你收集整理的[转]RxHttp 一条链发送请求,新一代Http请求神器(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。