Возврат пользовательского объекта из onError () Android Rx Java вместо бросаемого объекта - PullRequest
0 голосов
/ 30 мая 2018

Я новичок в RX Java.При реализации Rx Java с Retrofit я обнаружил, что в моем doOnError(){}

я получаю бросаемый объект, но я хочу, чтобы мой doOnError () из RX Java возвращал ErrorBase () -> это мой пользовательский класс.вместо * throwable.

это поможет мне обработать ошибку в центральном.я передам свой объект throwable в мой класс ErrorBase, где я обработал пользовательские сообщения.

Ниже doOnError().Где я хочу вернуть объект ErrorBase

apiInterface.getLoginDetails(auth)
        .doOnNext {
           //LoginResponse
        }
        doOnError{
        return ErrorBase(throwable)
          }

Код других классов.

Класс интерфейса API

interface ApiInterface {

@POST("login")
fun getLoginDetails(@Header(Constants.AUTHORIZATION) auth: String): Observable<LoginResponseModel>
} 

LoginRepository

class LoginRepository @Inject constructor(private val apiInterface: ApiInterface,
                                      val utils: Utils) {


fun getLoginDetails(auth: String): Observable<LoginResponseModel> {

    return apiInterface.getLoginDetails(auth)
            .doOnNext {
            }
            .doOnError {
              //Right now having throw-able object
            }

}
}

ErrorBase

class ErrorBase(private val throwable: Throwable) {

private var message: String?
private var statusCode: Int


init {
    statusCode = getStatusCode()
    message = getMessage()
}

private fun getStatusCode(): Int {
    if (throwable is HttpException) {
        val exception = throwable
        return exception.code()
    }
    return -1
}

private fun getMessage() =
        when (throwable) {
            is IOException -> "Something Went Wrong"
            is UnknownHostException -> "No internet connectivity"
            is SocketTimeoutException -> "Slow Internet connectivity"
            else -> throwable.message
        }
}

LoginvViewModel

class LoginViewModel @Inject constructor(
    private val loginRepository: LoginRepository) : ViewModel() {
private val TAG = this.javaClass.name
private var loginResult: MutableLiveData<LoginResponseModel> = MutableLiveData()
private var loginError: MutableLiveData<String> = MutableLiveData()
private var loginLoader: MutableLiveData<Boolean> = MutableLiveData()

private lateinit var disposableObserver: DisposableObserver<LoginResponseModel>

fun loginResult(): LiveData<LoginResponseModel> {
    return loginResult
}

fun loginError(): LiveData<String> {
    return loginError
}

fun loginLoader(): LiveData<Boolean> {
    return loginLoader
}


private fun getLoginData(auth: String) {
    loginLoader.postValue(true)
    initLoginObserver()
    loginRepository.getLoginDetails(auth)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .debounce(400, MILLISECONDS)
            .subscribe(disposableObserver)
}

private fun initLoginObserver() {
    disposableObserver = object : DisposableObserver<LoginResponseModel>() {
        override fun onComplete() {

        }

        override fun onNext(loginDetails: LoginResponseModel) {
            loginResult.postValue(loginDetails)
            loginLoader.postValue(false)
        }

        override fun onError(e: Throwable) {
            loginError.postValue(e.message)
            loginLoader.postValue(false)
        }
    }
}

fun disposeElements() {
    if (null != disposableObserver && !disposableObserver.isDisposed) disposableObserver.dispose()
}

fun loginClicked() {
    getLoginData("auth")
}}

1 Ответ

0 голосов
/ 30 мая 2018

Во-первых, doOnError не предназначен для преобразования / возврата некоторых данных, но помогает справиться с побочными эффектами, такими как ведение журнала.

Во-вторых, ErrorBase плохо сочетается с LoginResponseModel потому что у них нет общих родителей.

Таким образом, я предлагаю вам следующее решение:

  1. Создайте один базовый класс для вашего ответа:

    sealed class LoginResponse {
    
        class Result( ..your data here.. ) : LoginResponse()
    
        class Error( ... ) : LoginResponse()
    }
    
  2. Выполните возврат функции LoginResponse и выполните следующие изменения:

    fun getLoginDetails(auth: String): Observable<LoginResponse> {
        return apiInterface.getLoginDetails(auth)
                   .map { data -> LoginResponse.Result(data) }
                   .onErrorReturn { throwable -> LoginResponse.Error(throwable) }
    }
    
  3. Теперь оба результата имеют одного общего родителя, и вы можете использовать getLoginDetailsследующим образом:

    fun doRequest() {
         loginRepository.getLoginDetails(auth)
             .subscribe { result ->
                  when (result) {
                       is LoginResponse.Result -> //do something with result
                       is LoginResponse.Error -> //do something with error
                  }
             }
    }
    

Некоторое объяснение.

  • onErrorReturn делает именно то, что вам нужно - возвращает ваше пользовательское значение в случаеесли возникает ошибка

  • Если вы не добавите LoginResponse, вы должны сделать Observable<Any>, который напечатан свободно и не очень хорошо описывает ваш интерфейс.

  • Создание LoginResponse загерметизировано позволяет проверить только в 2 случаях, являются ли испущенные данные Result или Error.В противном случае компилятор Kotlin заставляет вас добавить дополнительную else ветку

Обновление В случае, если вам нужно сделать одно и то же в нескольких местах, вы можете пойти с этим:

sealed class Response<T> {

    data class Result<T>(val result: T) : Response<T>()

    data class Error<T>(val throwable: Throwable) : Response<T>()
}

fun getLoginDetails(auth: String): Observable<Response<LoginResponseModel>> {
    return apiInterface.getLoginDetails(auth)
               .map<Response<LoginResponseModel>> { data -> Response.Result(data) }
               .onErrorReturn { throwable -> LoginResponse.Error(throwable) }
}

..and somewhere in your code..

fun handleResponse(response: Response<LoginData>) {
    when (response) {
        is Response.Result -> response.result
        is Response.Error -> response.throwable
    }
}
...