Как использовать RxJava в обычном вызове модернизации?

#android #retrofit2 #rx-java2

#Android #retrofit2 #rx-java2

Вопрос:

Контекст: Мое текущее приложение использует обычный retrofit calls для получения данных из api . Я действительно хотел внедрить RX в вызовы, но у меня нет большого опыта в этом. Я прочитал кое-что в Интернете, и ни один из них не показал мне простого способа сделать это. Я покажу вам, что у меня есть.

Цель: Превратить то, что у меня есть, в RXJava

Это мой код :

Мой общий метод выполнения вызова, который я хочу преобразовать в RXJava :

 fun <T> performCall(call: Call<T>?, callback: OnRequestCallback<T>) {
        call?.enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                when (response.code()) {
                    200, 201 -> {
                        callback.onSuccess(response.body())
                    }
                    else -> {
                        callback.onError(response.errorBody())
                    }
                }
                return
            }

            override fun onFailure(call: Call<T>, t: Throwable) {
                callback.onError(null)
                Log.d("Network Manager Failure", t.localizedMessage)
            }
        })
    }
  

Затем, чтобы получить контекст из моей активности, я использую этот метод, который вызывает метод выполнения вызова:

 fun <T> BaseActivity.callAPI(call: Observable<T>?, onSucceed: (T?) -> Unit, onError: (errorCode: String) -> Unit) {
    NetworkManager.instance.performCall(call,
        object : NetworkManager.OnRequestCallback<T> {
            override fun onSuccess(body: T?) {
                onSucceed(body)
            }

            override fun onError(errorResponseBody: ResponseBody?) {
                JSONObject(errorResponseBody?.string()).let {
                    val errorCode = it.getJSONObject("meta").getString("errorCode")
                    when (errorCode) {
                        Errors.DEPRECATED_API_VERSION.name ->
                            onAppUpdateNeeded()

                        else -> onError(errorResponseBody)
                    }
                }
            }
        })
}
  

Тогда BaseActivitt.callApi() используется в каждом действии, которому требуется информация api, я сейчас лучше использую view models dagger , но пока это то, что у меня есть, и я должен это сохранить.

Может кто-нибудь показать мне, как превратить это в RXJava/Kotlin вещь?

Комментарии:

1. Вам не нужно выполнять преобразование вручную. Retrofit может возвращать Observable . Просто взгляните на это простое объяснение

2. Да, но в моем вызове perform я действительно хотел использовать методы Rx вместо стандартных, предоставляемых retrofit, чтобы подготовить приложение к будущему

3. вам нужно изменить определение callAPI . Он не должен принимать обратные вызовы. Он должен вернуть наблюдаемое, и тогда вызывающий абонент подпишется. Таким образом, вы сможете объединить observable. То же самое для performCall . С RxJava вы должны стараться всегда возвращать observable, а затем подписываться в конце канала.

4. Можете ли вы показать пример @kingston?

5. Ммм, здесь действительно сложно сделать что-то лучшее, чем то, что вы можете найти в Google «rxjava api call». В любом случае ваш фрагмент не будет компилироваться: параметр call определяется по-разному.

Ответ №1:

Честно говоря, мне не нравится идея иметь эти универсальные обработчики. Мне пришлось работать над проектом, который был написан подобным образом, и это был не самый приятный опыт: что произойдет, если, например, вы захотите по-другому обработать Errors.DEPRECATED_API_VERSION для вызова?

В любом случае, я бы сделал что-то вроде этого: из Retrofit верните наблюдаемое, а затем в том месте, где вам нужно выполнить вызов, подпишитесь на наблюдаемое.

 val disposable = service
        .yourApi()
        .map { value ->
            MyCommand.SuccessCommand(value)
        }
        .onErrorResumeNext { ex: Throwable -> YourObservableThatEmitsTheErrorCommandOrTheOnAppUpdateNeededCommand() }
        .subscribe { command: MyCommand ->
            when (command) {
                is MyCommand.SuccessCommand -> {
                }
                is MyCommand.ErrorCommand -> {

                }
                is MyCommand.AppUpdateNeededCommand -> {

                }
            }
        }
  

Команда может быть реализована примерно так

 sealed class MyCommand {
    class SuccessCommand<T> (value: T): MyCommand()
    class ErrorCommand (val ex: Exception): MyCommand()
    object AppUpdateNeededCommand: MyCommand()
}
  

Комментарии:

1. Пожалуйста, учтите, что я написал это здесь, поэтому отнеситесь к этому со всей серьезностью, и это всего лишь один из тысяч способов его реализации

2. И, конечно, вы можете поместить все, что находится перед subscribe, в класс уровня данных / репозитория