#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, в класс уровня данных / репозитория