一些背景:我是RxJava的新手,我正在尝试在应用程序中创建一个可以脱机工作并在有网络时同步的功能。我正在尝试将多个操作链接起来,但我并不精通如何将不同类型如Completable,Maybe和Observable链接在一起。
以下是用户添加或更新某些数据后需要在订单中完成的操作列表:
以下是每项操作的方法:
更新本地数据库:
private Completable setStatus(Entity entity, Entity.Status status){
entity.setStatus(status);
return Completable.fromAction(() -> localDataStore.updatePersonalPlace(personalPlaceEntity));
}
将文件上传到FirebaseStorage
RxFirebaseStorage.putBytes(storageRef, bytes); // returns a Maybe<TaskSnapshot>
在firebase数据库中设置数据
RxFirebaseDatabase.setValue(dataRef, model); // returns a Completable
我试过
setStatus(...)
.toObservable()
.map(o -> uploadFile())
.map(fileUrl -> updateFirebaseDatabase(fileUrl))
.doOnNext(() -> setStatus(..) ) // set status to synced
.subscribe(() -> Timber.d("Data updated",
t -> setStatus(..)); // set status back to what it was on error
但这不起作用,我认为我并不真正理解如何将这些操作链接起来的基本原理。 toObservable之后的所有操作都不会被调用。
我还试图将maybe转换为可填充的并使用Completable.andThen
链接它们但我不确定如何正确地执行此操作并且我需要返回fileUrl来更新firebase数据库。
有人可以指出我正确的方向,我应该在这里使用什么。这是一个相当简单的任务,现在感觉很复杂,也许我的方法是非常错误的。
谢谢,
答案 0 :(得分:2)
我在您的代码中添加了一些注释:
setStatus(...) // completable => (onError|onComplete)?
.toObservable() // => will call (onError|onComplete)? (beacause of the nature of completable)
.map(o -> uploadFile()) // never call because no item is emitted (completable...)
.map(fileUrl -> updateFirebaseDatabase(fileUrl)) // never call too
.doOnNext(() -> setStatus(..) ) // set status to synced // never call too
.subscribe(..)
您必须为Completable
更改Single
并返回true
之类的内容。
答案 1 :(得分:1)
设置状态会返回snapshot.children
,只会调用database.child("messages").queryOrdered(byChild: "timestamp").observe(.value, with: { snapshot in
for child in snapshot.children.allObjects as! [DataSnapshot] {
print("\(child.key)")
}
completionHandler(true)
})
或Completable
。您的onComplete
和onError
永远不会被调用,因为它永远不会发出任何项目。您可能希望使用map
或使用可以链接Completables的doOnNext
,doOnComplete
或concatArray
。
答案 2 :(得分:0)
感谢Kevinrob和cwbowron的回答,我能够弄清楚出了什么问题。
setStatus现在返回一个Single:
private Single<Integer> setStatus(Entity entity, Entity.Status status){
entity.setStatus(status);
return Single.fromCallable(() -> localDataStore.updatePersonalPlace(personalPlaceEntity));
}
这将返回一个可填写的:
最后将实体状态更新为在本地数据库中同步。
return setPlaceStatusSingle(entity, Entity.Status.SYNCING)
.subscribeOn(Schedulers.io())
.toObservable()
.map(integer -> BitmapUtils.convertBitmapToByteArray(entity.getPhoto()))
.doOnNext(bytes -> Timber.d("Converted bitmap to bytes"))
.flatMap(bytes -> RxFirebaseStorage.putBytes(fileRef, bytes).toObservable())
// Using flatmap to pass on the observable downstream, using map was a mistake which created a Single<Observable<T>>
.observeOn(Schedulers.io())
.doOnNext(taskSnapshot -> Timber.d("Uploaded to storage"))
.map(taskSnapshot -> taskSnapshot.getDownloadUrl().toString()) // Firebase stuff, getting the photo Url
.flatMapCompletable(photoUrl -> {
Timber.d("Photo url %s", photoUrl);
model.setPhotoUrl(photoUrl);
return RxFirebaseDatabase.setValue(ref, model);
})
// Passes the Completable returned from setValue downstream
.observeOn(Schedulers.io())
.doOnComplete(() -> {
entity.setStatus(Entity.Status.SYNCED);
entity.setPhotoUrl(model.getPhotoUrl());
localDataStore.updateEntity(entity);
})
.doOnError(throwable -> onErrorUpdatingEntity(entity, throwable));