首页 > 解决方案 > 如何在 Android 应用程序中执行对 REST API 的调用序列?

问题描述

我很难调用我的 api。我将 Reactivex 与 kotlin 和 Flowables 一起使用。如果我通过“If-Modified_since”标头传递的日期小于上次更新,我的 API 会返回一个项目列表。如果没有更新,我将作为应用返回 android 应用 304 错误。

我需要执行以下程序。1->我调用api 2->如果调用成功,将列表保存在Realm中并返回viewmodel 3->如果错误是304,我对item进行缓存搜索(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
                }

问题是,最好的方法是什么?

谢谢你。

标签: androidkotlinrx-javareactivex

解决方案


我的大部分评论都是我的解释。

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()
    }

}

推荐阅读