簡體   English   中英

RXJava 2-使用領域和改造來獲取數據

[英]Rxjava 2 - fetch data with realm and retrofit

任務:我想先獲取本地數據。 如果返回的數據為空,我想調用API服務。

主講人

private fun getData() {
    val disposable = dataRepository.getDataFromRepository(String: itemId)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ _ ->
                // I got my data
            }, {
                // error
            })
    compositeDisposable.add(disposable)
}

資料儲存庫

fun getDataFromRepository(itemId: String): Single<Data> {
    val dataAsSingle: Single<Event>

    //fetch data locally
    dataAsSingle = getDataLocally(itemId)

    //if nothing was found locally, call api service to fetch data
    if (dataAsSingle == null) {
        getDataFromApi(itemId)
    }

    return dataAsSingle
}

private fun getDataLocally(itemId: String): Single<Data> {
    var data: Data? = null

    val realm = Realm.getDefaultInstance()
        data = realm.where(Data::class.java).equalTo(itemId)
    // some other logic..
    realm.close()

    return data?.let {
        Single.just(data)
    } ?: Single.error(NoSuchEventFoundException())
}

private fun getDataFromApi(itemId: String): Single<Data> {
    return dataService.getDataFromApiCall(itemId)
            .onErrorResumeNext(ErrorHandler(BaseErrorParser()))
            .map { apiResponse ->
                    //some logic blah blah blah...
                    return@map data
                } 
            }
}

好吧,我認為我的方法是錯誤的,但是我不能一開始就告訴您原因。。。這個方法還可以,但是似乎它跳過了RxJava的要點。 也許有人可以解釋如何使用RxJava 2以正確的模式和方法解決此問題?

更新

資料儲存庫

fun getDataFromRepository(itemId: String): Single<Data> {

    val localData: Observable<Data> = getDataLocally(itemId)
    val remoteData: Observable<Data> = getDataFromApi(itemId)
           .doOnNext(

            })

    return Observable
            .concat(localEvent, remoteEvent)
            .first()
}

private fun getDataLocally(itemId: String): Observable<Data> {
    var data: Data? = null

    val realm = Realm.getDefaultInstance()
        data = realm.where(Data::class.java).equalTo(itemId)
    // some other logic..
    realm.close()

    return Observable.just(data)
}

private fun getDataFromApi(itemId: String): Observable<Data> {
    return dataService.getDataFromApiCall(itemId)
            .map { apiResponse ->
                    //some logic blah blah blah...
                    return@map data
                } 
            }
}

您可以使用concat運算符。 重要的部分是您不應從本地源返回空值。 您應該返回Empty Observable以獲取遠程呼叫。 這是一個示例代碼:

final Observable<Page> localResult = mSearchLocalDataSource.search(query);
final Observable<Page> remoteResult = mSearchRemoteDataSource.search(query)
                .doOnNext(new Action1<Page>() {
                    @Override
                    public void call(Page page) {
                        if (page != null) {
                            mSearchLocalDataSource.save(query, page);
                            mResultCache.put(query, page);
                        }
                    }
                });

        return Observable.concat(localResult, remoteResult)
                .first()
                .map(new Func1<Page, Page>() {
                    @Override
                    public Page call(Page page) {
                        if (page == null) {
                            throw new NoSuchElementException("No result found!");
                        }
                        return page;
                    }
});

實際上,使用Realm執行此操作的正確方法是偵聽Realm中的更改,如果Realm不包含您要查找的內容,則從API的后台線程更新Realm

(在從UI線程使用此方法的限制下,以便將RealmResults接收到UI線程-這樣,您可以使用異步事務並監聽Realm中的更改):

private fun getData() {
    val disposable = dataRepository.getDataFromRepository(String: itemId)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ _ ->
                // I got my data
            }, {
                // error
            })
    compositeDisposable.add(disposable)
}

哪里:

fun getDataFromRepository(itemId: String): Observable<Data> =
    Observable.create { emitter ->
        val realm = Realm.getDefaultInstance()
        val results = realm.where<Data>().equalTo("itemId", itemId).findAllAsync()
        val listener = RealmChangeListener { results ->
            if(!emitter.isDisposed()) {
                emitter.onNext(results)
            }
        }
        emitter.setDisposable(Disposable {
            results.removeChangeListener(listener)
            realm.close()
        })
        results.addChangeListener(listener)
    }.subscribeOn(AndroidSchedulers.mainThread())
    .doOnNext { results ->
        if(results.isEmpty()) {
            dataService.getDataFromApiCall(itemId)
                       // .toSingle() // ensure this completes automatically, but only if it's not a single already
                       .subscribeOn(Schedulers.io())
                       .subscribeWith(object: DisposableObserver<>() {
                           fun onNext(data: Data) {
                               Realm.getDefaultInstance().use { realm ->
                                  realm.executeTransaction { realm ->
                                      realm.insert(data)
                                   }
                               }
                           }

                           fun onError(throwable: Throwable) {
                               ... /* do something */ 
                           }
                      )
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM