2021年1月6日星期三

Android kotlin Rxjava + Retrofit with http request handle error with retryWhen and customer exception not work

is there anyone can help? I meet some problem that I would like to handle the connect error return by server response.

Like this :

When I request to server and I get some json like below:

 {"Data":null,"Result":{"State":-2,"Msg":"Parameter input from user error."}}  

I would like to handle this by Rxjava with retryWhen

Then , I write some Observer to handle some parse error or something wrong from server .

abstract class RetrofitResultObserver<T> : Observer<Result<T>> {        override fun onSubscribe(d: Disposable) {}        override fun onComplete() {        }        override fun onError(e: Throwable) {  //        e.printStackTrace()          val resultException: RetrofitResultException            //non-200 error          if (e is HttpException) {              resultException = RetrofitResultException(e.code(), "non-200 HTTP ERROR", e)              Log.e(TAG, "Retrofit Http Error")              onFailure(resultException)          } else if (e is IOException) {              resultException = RetrofitResultException(0, "NETWORK ERROR", e)              Log.e(TAG, "Retrofit Network Error")              onFailure(resultException)          } else if (e is UnknownFormatConversionException || e is JsonIOException || e is JsonParseException) {              resultException = RetrofitResultException(RetrofitResultException.PARSE_ERROR, "PARSE ERROR", e)              Log.e(TAG, "Retrofit Parse Error")              onFailure(resultException)          } else if(e is RetrofitResultException){              Log.e(TAG, "RetrofitResultException , ${e.code} , ${e.msg}")              onFailure(e)          }          else{              returnUnKnow(e)          }      }        private fun returnUnKnow(e: Throwable) {          Log.d(TAG, e.toString())          val resultException = RetrofitResultException(RetrofitResultException.UNKNOWN, "UNKNOWN ERROR", e)          //        ToastUtils.showShort("UnKnow error");          onFailure(resultException)      }        override fun onNext(t: Result<T>) {            if (t == null) {              onError(RetrofitResultException(RetrofitResultException.PARSE_ERROR, "Return null result from server"))              return          }            val result = t.result            if (result?.code == null) {              onError(RetrofitResultException(RetrofitResultException.PARSE_ERROR, "Return null data from server"))              return          }            //        Result result = (Result)t;            if (Constants.Http.SUCCESS === t.result!!.code) {              try {                  onSuccess(t.value!!)              } catch (e: Exception) {                  e.printStackTrace()              }            } else {              onResultCode(t.result!!.code)            }      }        /**       * call this when getting non SUCCESS code       */      protected fun onResultCode(resultCode: Int) {          Log.d(TAG, "server result [$resultCode]")          onError(RetrofitResultException(resultCode, "Return error result from server"))      }        open fun onFailure(e: RetrofitResultException) {            e.printStackTrace()      }        abstract fun onSuccess(data: Collection<T>)          class RetrofitResultException : RuntimeException {          var code: Int = 0          var msg: String            constructor(code: Int, msg: String) {              this.code = code              this.msg = msg          }            constructor(code: Int, msg: String, e: Throwable) {              this.code = code              this.msg = msg          }            override fun toString(): String {              return "http code = " + code + "\n cause = " + msg + "\n" + super.toString()          }            companion object {                const val UNKNOWN = 1000              const val PARSE_ERROR = 1001              const val RESULT_CODE_ERROR = 1002          }      }        companion object {            const val TAG = "RetrofitResult"      }  }    

All handle by Observer is work fine ,

But I have some problem with here :

I write the kotlin extension to a handle error by retryWhen

  fun <T> Observable<T>.retryWhenError(retryCount: Int, delayInSeconds: Long): Observable<T> {          return retryWhen { errors ->                     errors.zipWith(                      Observable.range(1, retryCount), BiFunction { throwable: Throwable, count: Int -> Pair(throwable, count) })                      .flatMap { count: Pair<Throwable, Int> ->                          LogTool.e("test ${count.first}")                          LogTool.e("test ")                          if (count.second < retryCount) {                              Observable.timer(delayInSeconds, TimeUnit.SECONDS)                          } else {                              Observable.error(count.first)                          }                      }          }      }  

But when I test it and server return the error code like this with my Observer and run the onError()

Which I call my http API:

fun fetchGpsApi(fetchGPSRequest: FetchGPSRequest, result: RetrofitResultObserver<FetchGPSResult>) {            repo.fetchGps(fetchGPSRequest)                  .retryWhenError(2,5)                  .subscribeOn(Schedulers.io())                  .observeOn(AndroidSchedulers.mainThread())                  .subscribe(result)        }  

Which server return:

 {"Data":null,"Result":{"State":-2,"Msg":"Parameter input from user error."}}  

And I see the log I print on my extension function is always not show, mean that doesn,t go into the retryWhenError Extension ...

How can I fix this problem ? Can any god coder can help?

https://stackoverflow.com/questions/65606118/android-kotlin-rxjava-retrofit-with-http-request-handle-error-with-retrywhen-a January 07, 2021 at 11:06AM

没有评论:

发表评论