Detailed explanation of how to deal with network anomalies by using Kotlin

  • 2021-09-20 21:29:08
  • OfStack

1. Preface

The previous article RxJava's Several Ways of Handling Business Exceptions has introduced that Retrofit's exceptions can be handled in a variety of ways.

Among them, you can use the error handling operators of RxJava, which are specifically used to handle exceptions.

Just give a random example of two operators:

The onErrorReturn operator, which indicates that when an error occurs, it emits a default value and ends the data stream. Therefore, Subscriber can't see the exception information, but can see the normal data flow end state.

onErrorResumeNext operator, indicating that when an error occurs, another data stream is used to continue transmitting data. You can't see the error message in the returned observer.

2. Use the features of Kotlin

This time, I combined the features of Kotlin extension function to try to handle exceptions.

Most of the Response returned by the network request takes the following form:


{
 "code":0,
 "message":"success",
 "data":{
 ...
 }
}

For client development, we will encapsulate HttpResponse of a base class.


data class HttpResponse<T>(
 var code: Int = -1, //0:  Success  1: xxx Error or expired  2:  Business logic error  500: Internal system error  998 Denote Token Invalid 
 var message: String? = null,
 var data: T? = null
) : UnProguard {
 val isOkStatus: Boolean
 get() = code == 0
}

Among them, UnProguard is an empty interface, which is mainly convenient for App to keep some classes when confused.


interface UnProguard : Serializable

Normally, we would handle exceptions in onError of Observer as follows:


 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() })

If we use the error handling operator of RxJava, we can write the following extension function:


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 < Describe the features of the current version >
 */

/**
 *  Try to retry 
 *  Default is 3 The second retry opportunity, the delay time of each retry is 1000ms
 */
fun <T> Maybe<T>.retryWithDelayMillis(maxRetries: Int=3, retryDelayMillis: Int=1000): Maybe<T> =
 this.retryWhen(RetryWithDelay(maxRetries,retryDelayMillis))

/**
 *  When an error is encountered, the exception can be caught in advance and emitted 1 The default value of. 
 *  There is no need to do exception handling later 
 */
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
}

/**
 *  When an error is encountered, the exception can be caught in advance and returned 1 A new one Maybe
 *  There is no need to do exception handling later 
 */
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())

Use of extension function 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()
   }
  }

This eliminates the need to handle exceptions in onError, and errorReturn is a higher order function. Its action parameter passes a function, which is specially used to handle exceptions. The exception handling of every 1 network request will not be the same. You can use this function to pass different exception handling.

Summarize

Reasonable use of Kotlin extension functions, you can write elegant code. By using higher-order functions, one step of abstraction can be achieved.


Related articles: