用Kotlin的方式來處理網路異常

Tony沈哲發表於2019-03-01
森林的夢想.jpg

一. 前言

之前的文章 RxJava處理業務異常的幾種方式 曾經介紹過 Retrofit 的異常可以有多種處理方式。

其中,可以使用 RxJava 的錯誤處理操作符,它們是專門用來處理異常的。

隨便例舉兩個操作符:

onErrorReturn 操作符,表示當發生錯誤的時候,發射一個預設值然後結束資料流。所以 Subscriber 看不到異常資訊,看到的是正常的資料流結束狀態。

onErrorResumeNext 操作符,表示當錯誤發生的時候,使用另外一個資料流繼續發射資料。在返回的被觀察者中是看不到錯誤資訊的。

二. 使用 Kotlin 的特性

這次我結合 Kotlin 擴充套件函式的特性來嘗試處理異常。

網路請求返回的 Response 大多是採用如下這種形式:

{
   "code":0,
   "message":"success",
   "data":{
       ...
    }
}
複製程式碼

對於客戶端開發而言,我們會封裝一個基類的HttpResponse。

data class HttpResponse<T>(
        var code: Int = -1, //0: 成功 1: xxx錯誤或過期 2: 業務邏輯錯誤 500:系統內部錯誤 998表示Token無效
        var message: String? = null,
        var data: T? = null
) : UnProguard {
    val isOkStatus: Boolean
        get() = code == 0
}
複製程式碼

其中,UnProguard是一個空的介面,主要是方便 App 在混淆的時候保留部分類。

interface UnProguard : Serializable
複製程式碼

通常情況下,我們會在 Observer 的 onError 中按照如下的方式處理異常:

        viewModel.getHelps(this)
                .subscribe({
                    if (it.isOkStatus) {
                        multi_status_view.showContent()
                        adapter.addData(it.data?.list)
                    } else {
                        multi_status_view.showError()
                    }
                }, { multi_status_view.showError() })
複製程式碼

如果我們利用 RxJava 的錯誤處理操作符,可以編寫如下的擴充套件函式:

import com.safframework.utils.RetryWithDelay
import io.reactivex.Maybe


/**
 *
 * @FileName:
 *          cn.magicwindow.core.ext.`Maybe+Extension`.kt
 * @author: Tony Shen
 * @date: 2018-07-19 17:31
 * @version V1.0 <描述當前版本功能>
 */

/**
 * 嘗試重試
 * 預設有3次重試機會,每次的延遲時間是1000ms
 */
fun <T> Maybe<T>.retryWithDelayMillis(maxRetries: Int=3, retryDelayMillis: Int=1000): Maybe<T> =
        this.retryWhen(RetryWithDelay(maxRetries,retryDelayMillis))

/**
 * 遇到錯誤時,能夠提前捕獲異常,併發射一個預設的值。
 * 後面無須再做異常處理
 */
fun <T> Maybe<T>.errorReturn(defValue:T): Maybe<T> = this.onErrorReturn {

    it -> it.printStackTrace()
    return@onErrorReturn defValue
}

fun <T> Maybe<T>.errorReturn(defValue:T,action: (Throwable) -> Unit): Maybe<T> = this.onErrorReturn {

    action.invoke(it)

    return@onErrorReturn defValue
}

/**
 * 遇到錯誤時,能夠提前捕獲異常,並返回一個新的Maybe
 * 後面無須再做異常處理
 */
fun <T> Maybe<T>.errorResumeNext(defValue:T):Maybe<T> = this.onErrorResumeNext(Maybe.just(defValue))


fun <T> Maybe<T>.errorResumeNext():Maybe<T> = this.onErrorResumeNext(Maybe.empty())
複製程式碼

擴充套件函式 errorReturn 的使用:

        viewModel.getHelps(this)
                .errorReturn(HttpResponse()) {
                    multi_status_view.showError()
                }
                .subscribe{
                    if (it.isOkStatus) {
                        multi_status_view.showContent()
                        adapter.addData(it.data?.list)
                    } else {
                        multi_status_view.showError()
                    }
                }
複製程式碼

這樣無須在 onError 中處理異常,而且 errorReturn 還是一個高階函式。它的 action 引數傳遞的是一個函式,專門用於處理異常。每一個網路請求的異常處理並不會都一樣,可以用該函式來傳遞不同的異常處理。

總結

合理利用 Kotlin 的擴充套件函式,可以編寫優雅的程式碼。而使用高階函式,則可以達到的進一步的抽象。

該系列的相關文章:

Kotlin Coroutines 筆記 (二)


Java與Android技術棧:每週更新推送原創技術文章,歡迎掃描下方的公眾號二維碼並關注,期待與您的共同成長和進步。

用Kotlin的方式來處理網路異常

相關文章