[英]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.