Android RxJava應用:網絡請求出錯重連(結合Retrofit)

前言

Rxjava嗦锐,由于其基于事件流的鏈式調用沉御、邏輯簡潔 & 使用簡單的特點,深受各大 Android開發(fā)者的歡迎皂冰。

如果還不了解RxJava,請看文章:Android:這是一篇 清晰 & 易懂的Rxjava 入門教程

  • RxJava如此受歡迎的原因啊犬,在于其提供了豐富 & 功能強大的操作符灼擂,幾乎能完成所有的功能需求
  • 今天,我將為大家?guī)?Rxjava創(chuàng)建操作符的實際開發(fā)需求場景:網絡請求出錯重連需求 觉至,并結合RetrofitRxJava 實現剔应,希望大家會喜歡。

Carson帶你學RxJava系列文章语御,包括 原理峻贮、操作符、應用場景应闯、背壓等等纤控,請關注看文章:Android:這是一份全面 & 詳細的RxJava學習指南


目錄

示意圖

1. 需求場景

示意圖

2. 功能說明

  • 功能需求說明
示意圖

注:關于 Rxjava中的retryWhen() 操作符的使用請看文章Android RxJava:功能性操作符 全面講解

  • 功能邏輯
示意圖
  • 實例說明
    在本例子中:采用Get方法對 金山詞霸API 發(fā)送網絡請求
    1. 通過 斷開網絡連接 模擬 網絡異常錯誤(恢復網絡即可成功發(fā)送請求)
    2. 限制重試次數 = 10次
    3. 采用 Gson 進行數據解析
金山詞典

3. 具體實現

下面,我將結合 RetrofitRxJava 實現 網絡請求出錯重連 功能

3.1 步驟說明

  1. 添加依賴
  2. 創(chuàng)建 接收服務器返回數據 的類
  3. 創(chuàng)建 用于描述網絡請求 的接口(區(qū)別于Retrofit傳統形式)
  4. 創(chuàng)建 Retrofit 實例
  5. 創(chuàng)建 網絡請求接口實例 并 配置網絡請求參數(區(qū)別于Retrofit傳統形式)
  6. 發(fā)送網絡請求(區(qū)別于Retrofit傳統形式)
  7. 發(fā)送網絡請求
  8. 對返回的數據進行處理

下面碉纺,將進行詳細的功能說明船万。

本實例側重于說明 RxJava 的輪詢需求刻撒,關于Retrofit的使用請看文章:這是一份很詳細的 Retrofit 2.0 使用教程(含實例講解)

3.2 步驟實現

步驟1: 添加依賴

a. 在 Gradle加入Retrofit庫的依賴

build.gradle

dependencies {

// Android 支持 Rxjava
// 此處一定要注意使用RxJava2的版本
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

// Android 支持 Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'

// 銜接 Retrofit & RxJava
// 此處一定要注意使用RxJava2的版本
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

// 支持Gson解析
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

}

b. 添加 網絡權限
AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
步驟2:創(chuàng)建 接收服務器返回數據 的類
  • 金山詞霸API 的數據格式說明如下:
// URL模板
http://fy.iciba.com/ajax.php

// URL實例
http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world

// 參數說明:
// a:固定值 fy
// f:原文內容類型,日語取 ja耿导,中文取 zh声怔,英語取 en,韓語取 ko舱呻,德語取 de醋火,西班牙語取 es,法語取 fr箱吕,自動則取 auto
// t:譯文內容類型芥驳,日語取 ja,中文取 zh茬高,英語取 en兆旬,韓語取 ko,德語取 de雅采,西班牙語取 es爵憎,法語取 fr慨亲,自動則取 auto
// w:查詢內容
  • 示例
API格式說明
  • 根據 金山詞霸API 的數據格式婚瓜,創(chuàng)建 接收服務器返回數據 的類:

Translation.java

public class Translation {

    private int status;

    private content content;
    private static class content {
        private String from;
        private String to;
        private String vendor;
        private String out;
        private int errNo;
    }

    //定義 輸出返回數據 的方法
    public void show() {
        Log.d("RxJava", content.out );
    }
}
步驟3:創(chuàng)建 用于描述網絡請求 的接口

采用 注解 + Observable<...>接口描述 網絡請求參數

GetRequest_Interface.java

public interface GetRequest_Interface {

    @GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20world")
    Observable<Translation> getCall();
     // 注解里傳入 網絡請求 的部分URL地址
    // Retrofit把網絡請求的URL分成了兩部分:一部分放在Retrofit對象里,另一部分放在網絡請求接口里
    // 如果接口里的url是一個完整的網址刑棵,那么放在Retrofit對象里的URL可以忽略
    // 采用Observable<...>接口 
    // getCall()是接受網絡請求數據的方法
}
接下來的步驟均在RxJavafixRxjava.java內實現(請看注釋)

RxJavafixRxjava.java

public class RxJavafixRetrofit2 extends AppCompatActivity {

    private static final String TAG = "RxJava";

    // 設置變量
    // 可重試次數
    private int maxConnectCount = 10;
    // 當前已重試次數
    private int currentRetryCount = 0;
    // 重試等待時間
    private int waitRetryTime = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 步驟1:創(chuàng)建Retrofit對象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fy.iciba.com/") // 設置 網絡請求 Url
                .addConverterFactory(GsonConverterFactory.create()) //設置使用Gson解析(記得加入依賴)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava
                .build();

        // 步驟2:創(chuàng)建 網絡請求接口 的實例
        GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

        // 步驟3:采用Observable<...>形式 對 網絡請求 進行封裝
        Observable<Translation> observable = request.getCall();

        // 步驟4:發(fā)送網絡請求 & 通過retryWhen()進行重試
        // 注:主要異常才會回調retryWhen()進行重試
        observable.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
                // 參數Observable<Throwable>中的泛型 = 上游操作符拋出的異常巴刻,可通過該條件來判斷異常的類型
                return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {

                        // 輸出異常信息
                        Log.d(TAG,  "發(fā)生異常 = "+ throwable.toString());

                        /**
                         * 需求1:根據異常類型選擇是否重試
                         * 即,當發(fā)生的異常 = 網絡異常 = IO異常 才選擇重試
                         */
                        if (throwable instanceof IOException){

                            Log.d(TAG,  "屬于IO異常蛉签,需重試" );

                            /**
                             * 需求2:限制重試次數
                             * 即胡陪,當已重試次數 < 設置的重試次數,才選擇重試
                             */
                            if (currentRetryCount < maxConnectCount){

                                // 記錄重試次數
                                currentRetryCount++;
                                Log.d(TAG,  "重試次數 = " + currentRetryCount);

                                /**
                                 * 需求2:實現重試
                                 * 通過返回的Observable發(fā)送的事件 = Next事件碍舍,從而使得retryWhen()重訂閱柠座,最終實現重試功能
                                 *
                                 * 需求3:延遲1段時間再重試
                                 * 采用delay操作符 = 延遲一段時間發(fā)送,以實現重試間隔設置
                                 *
                                 * 需求4:遇到的異常越多片橡,時間越長
                                 * 在delay操作符的等待時間內設置 = 每重試1次妈经,增多延遲重試時間1s
                                 */
                                // 設置等待時間
                                waitRetryTime = 1000 + currentRetryCount* 1000;
                                Log.d(TAG,  "等待時間 =" + waitRetryTime);
                                return Observable.just(1).delay(waitRetryTime, TimeUnit.MILLISECONDS);


                            }else{
                                // 若重試次數已 > 設置重試次數,則不重試
                                // 通過發(fā)送error來停止重試(可在觀察者的onError()中獲取信息)
                                return Observable.error(new Throwable("重試次數已超過設置次數 = " +currentRetryCount  + "捧书,即 不再重試"));

                            }
                        }

                        // 若發(fā)生的異常不屬于I/O異常吹泡,則不重試
                        // 通過返回的Observable發(fā)送的事件 = Error事件 實現(可在觀察者的onError()中獲取信息)
                        else{
                            return Observable.error(new Throwable("發(fā)生了非網絡異常(非I/O異常)"));
                        }
                    }
                });
            }
        }).subscribeOn(Schedulers.io())               // 切換到IO線程進行網絡請求
                .observeOn(AndroidSchedulers.mainThread())  // 切換回到主線程 處理請求結果
                .subscribe(new Observer<Translation>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(Translation result) {
                        // 接收服務器返回的數據
                        Log.d(TAG,  "發(fā)送成功");
                        result.show();
                    }

                    @Override
                    public void onError(Throwable e) {
                        // 獲取停止重試的信息
                        Log.d(TAG,  e.toString());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

    }
}

3.3 測試結果

  1. 一開始先通過 斷開網絡連接 模擬 網絡異常錯誤,即開始重試经瓷;
  2. 等到第3次重試后恢復網絡連接爆哑,即無發(fā)生網絡異常錯誤,此時重試成功
示意圖

4. Demo地址

Carson_Ho的Github地址 = RxJava2實戰(zhàn)系列:出錯重連


5. 總結

  • 本文主要講解了 Rxjava創(chuàng)建操作符的實際開發(fā)需求場景:網絡請求出錯重連需求 舆吮,并結合RetrofitRxJava 實現
  • Carson帶你學RxJava系列文章:

入門
Carson帶你學Android:這是一篇清晰易懂的Rxjava入門教程
Carson帶你學Android:面向初學者的RxJava使用指南
Carson帶你學Android:RxJava2.0到底更新了什么揭朝?
原理
Carson帶你學Android:圖文解析RxJava原理
Carson帶你學Android:手把手帶你源碼分析RxJava
使用教程:操作符
Carson帶你學Android:RxJava操作符教程
Carson帶你學Android:RxJava創(chuàng)建操作符
Carson帶你學Android:RxJava功能性操作符
Carson帶你學Android:RxJava過濾操作符
Carson帶你學Android:RxJava組合/合并操作符
Carson帶你學Android:RxJava變換操作符
Carson帶你學Android:RxJava條件/布爾操作符
實戰(zhàn)
Carson帶你學Android:什么時候應該使用Rxjava队贱?(開發(fā)場景匯總)
Carson帶你學Android:RxJava線程控制(含實例講解)
Carson帶你學Android:圖文詳解RxJava背壓策略
Carson帶你學Android:RxJava、Retrofit聯合使用匯總(含實例教程)
Carson帶你學Android:優(yōu)雅實現網絡請求嵌套回調
Carson帶你學Android:網絡請求輪詢(有條件)
Carson帶你學Android:網絡請求輪詢(無條件)
Carson帶你學Android:網絡請求出錯重連(結合Retrofit)
Carson帶你學Android:合并數據源
Carson帶你學Android:聯想搜索優(yōu)化
Carson帶你學Android:功能防抖
Carson帶你學Android:從磁盤/內存緩存中獲取緩存數據
Carson帶你學Android:聯合判斷


歡迎關注Carson_Ho的簡書

不定期分享關于安卓開發(fā)的干貨潭袱,追求短露筒、平、快敌卓,但卻不缺深度慎式。


請點贊!因為你的鼓勵是我寫作的最大動力趟径!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末瘪吏,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子蜗巧,更是在濱河造成了極大的恐慌掌眠,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幕屹,死亡現場離奇詭異蓝丙,居然都是意外死亡,警方通過查閱死者的電腦和手機望拖,發(fā)現死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門渺尘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人说敏,你說我怎么就攤上這事鸥跟。” “怎么了盔沫?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵医咨,是天一觀的道長。 經常有香客問我架诞,道長拟淮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任谴忧,我火速辦了婚禮很泊,結果婚禮上,老公的妹妹穿的比我還像新娘俏蛮。我一直安慰自己撑蚌,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布搏屑。 她就那樣靜靜地躺著争涌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辣恋。 梳的紋絲不亂的頭發(fā)上亮垫,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天模软,我揣著相機與錄音,去河邊找鬼饮潦。 笑死燃异,一個胖子當著我的面吹牛,可吹牛的內容都是我干的继蜡。 我是一名探鬼主播回俐,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼稀并!你這毒婦竟也來了仅颇?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤碘举,失蹤者是張志新(化名)和其女友劉穎忘瓦,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體引颈,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡耕皮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了蝙场。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凌停。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖李丰,靈堂內的尸體忽然破棺而出苦锨,到底是詐尸還是另有隱情,我是刑警寧澤趴泌,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站拉庶,受9級特大地震影響嗜憔,放射性物質發(fā)生泄漏。R本人自食惡果不足惜氏仗,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一吉捶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧皆尔,春花似錦呐舔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至流炕,卻和暖如春澎现,著一層夾襖步出監(jiān)牢的瞬間仅胞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工剑辫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留干旧,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓妹蔽,卻偏偏與公主長得像椎眯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子胳岂,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容