Как выполнить последовательность вызовов REST API в приложении Android? - PullRequest
0 голосов
/ 14 мая 2019

Мне трудно позвонить в мой API.Я использую Reactivex с kotlin и Flowables.Мой API возвращает список элементов, если дата, прошедшая через заголовок «If-Modified_since», меньше, чем при последнем обновлении.Если обновления нет, я получаю как приложение, возвращающее приложение для Android ошибку 304.

Мне нужно выполнить следующую процедуру.1-> Я звоню в API 2-> Если звонок успешен, сохраняю список в Realm и возвращаюсь в viewmodel. 3-> Если ошибка 304, я выполняю поиск в кеше (Realm) элементов 4-> Если это другая ошибка, я обычно возвращаю ошибку для ViewModel

Вот код ниже, но я не уверен, так ли это.

override fun getTickets(eventId: String): Flowable<List<Ticket>> {
        return factory
                .retrieveRemoteDataStore()
                .getTickets(eventId)
                .map {
                    saveTickets(it)
                    it
                }.onErrorResumeNext { t: Throwable ->
                    if (t is HttpException && t.response().code() == 304) {
                        factory.retrieveCacheDataStore().getTickets(eventId)
                    } else
                        //Should return error
                }

Вопросесть, какой лучший способ сделать это?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 14 мая 2019

Большинство моих комментариев - мои объяснения.

data class Ticket(val id:Int) { 
     companion object { 
         fun toListFrom(jsonObject: JSONObject): TICKETS { 
             /**do your parsing of data transformation here */
             return emptyList()
         }
     }
}

typealias TICKETS = List<Ticket>


class ExampleViewModel(): ViewModel() {

    private var error: BehaviorSubject<Throwable> = BehaviorSubject.create()
    private var tickets: BehaviorSubject<TICKETS> = BehaviorSubject.create()

    /**public interfaces that your activity or fragment talk to*/
    fun error(): Observable<Throwable> = this.error 
    fun tickets(): Observable<TICKETS> = this.tickets

    fun start() {

        fetch("http://api.something.com/v1/tickets/")
                .subscribeOn(Schedulers.io())
                .onErrorResumeNext { t: Throwable -> 
                    if (t.message == "304") {
                        get(3)
                    } else {
                        this.error.onNext(t)
                        /** this makes the chain completed gracefuly without executing flatMap or any other operations*/
                        Observable.empty()
                    }
                }
                .flatMap(this::insertToRealm)
                .subscribe(this.tickets)

    }

    private fun insertToRealm(tickets: TICKETS) : Observable<TICKETS> {
        /**any logic here is mainly to help you save into Realm**/
        /** I think realm has the option to ignore items that are already in the db*/
        return Observable.empty()
    }

    private fun get(id: Int): Observable<TICKETS> {
        /**any logic here is mainly to help you fetch from your cache**/
        return Observable.empty()
    }

    private fun fetch(apiRoute: String): Observable<TICKETS> {
        /**
         * boilerplate code 
           wether you're using Retrofit or Okhttp, that's the logic you 
           should try to have 
         * */
        val status: Int = 0
        val rawResponse = ""
        val error: Throwable? = null 

        val jsonResponse = JSONObject(rawResponse)
        return Observable.defer {
           if (status == 200) {
               Observable.just(Ticket.toListFrom(jsonResponse))
           }
            else if (status == 304) {
               Observable.error<TICKETS>(Throwable("304"))          
            }
            else {
                Observable.error<TICKETS>(error)
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        this.error = BehaviorSubject.create()
        this.tickets = BehaviorSubject.create()
    }

}
0 голосов
/ 14 мая 2019

Я собираюсь предположить, что вы используете Retrofit. Если это так, то вы можете заключить вызов getTickets в Single<Response<SomeModel>>. Таким образом, на первой карте вы можете проверить код ошибки, что-то из строк:

...getTickets(id)
  .map{ response -> 
        when {
response.isSuccessful && response.body!=null -> {
                                         saveTickets(it)
                                         it
} 
!response.isSuccessful && response.errorCode() == 304 -> {
factory.retrieveCacheDataStore().getTickets(eventId)
}
else -> throw IOException()
}
}

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

Надеюсь, это поможет!

...