使用Room和Firebase链接多个RxJava2操作

时间:2017-09-19 11:14:22

标签: android firebase rx-java2 android-room

一些背景:我是RxJava的新手,我正在尝试在应用程序中创建一个可以脱机工作并在有网络时同步的功能。我正在尝试将多个操作链接起来,但我并不精通如何将不同类型如Completable,Maybe和Observable链接在一起。

以下是用户添加或更新某些数据后需要在订单中完成的操作列表:

  1. 更新本地数据库的数据,只需将状态设置为同步,使用Room here。
  2. 将文件上传到Firebase存储。
  3. 获取文件网址并将数据更新到Firebase数据库。
  4. 更新本地数据库的数据,将状态设置为已同步
  5. 以下是每项操作的方法:

    更新本地数据库:

    private Completable setStatus(Entity entity, Entity.Status status){
        entity.setStatus(status);
        return Completable.fromAction(() -> localDataStore.updatePersonalPlace(personalPlaceEntity));
    }
    

    使用Rx2Firebase

    将文件上传到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数据库。

    有人可以指出我正确的方向,我应该在这里使用什么。这是一个相当简单的任务,现在感觉很复杂,也许我的方法是非常错误的。

    谢谢,

3 个答案:

答案 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。您的onCompleteonError永远不会被调用,因为它永远不会发出任何项目。您可能希望使用map或使用可以链接Completables的doOnNextdoOnCompleteconcatArray

答案 2 :(得分:0)

感谢Kevinrobcwbowron的回答,我能够弄清楚出了什么问题。

setStatus现在返回一个Single:

private Single<Integer> setStatus(Entity entity, Entity.Status status){
    entity.setStatus(status);
    return Single.fromCallable(() -> localDataStore.updatePersonalPlace(personalPlaceEntity));
}

这将返回一个可填写的:

  1. 将实体状态设置为在本地数据库中同步。
  2. 将位图转换为字节数组。
  3. 在Firebase存储上传照片。
  4. 获取照片网址。
  5. 更新Firebase数据库上的数据。
  6. 最后将实体状态更新为在本地数据库中同步。

    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));