反应方式中的状态变异

时间:2015-09-11 14:11:26

标签: android state reactive-programming rx-java rx-android

最近我开始使用Reactive extensions的硬件项目。我已经阅读了一些介绍和教程,但我仍然处于初级水平。根据{{​​3}}文章:

  

一切都是流

然而,我目前的理解(或心理障碍)告诉我,任何改变状态的操作(例如从存储库中删除数据)都不应该/返回流/可观察的。

关于我的域名的小背景:我有一个用于注册地理围栏的用例。从this开始,我会跟踪存储库中的活动地理围栏。有时应用程序需要删除地理围栏,因此实现此目的的基本步骤是:

  • 从存储库中检索地理围栏
  • 从设备中移除地理围栏
  • 从存储库移除地理围栏

我目前的解决方案如下:

geofenceRepository.get(id)
            .map(new Func1<Geofence, String>() {
                @Override
                public String call(Geofence geofence) {
                    geofenceRepository.delete(geofence.getId()); // synchronous call here
                    return geofence.getRequestId();
                }
            })
            .toList()
            .flatMap(new Func1<List<String>, Observable<Status>>() {
                @Override
                public Observable<Status> call(List<String> ids) {
                    return locationProvider.removeGeofences(ids);
                }
            });

其中Geofence是我的自定义数据结构,locationProvider来自geofences do not survive reboot

您会注意到数据检索是以stream / observable的形式实现的,与delete不同。

上面例子中我不喜欢的是:带this nice library的地图运算符

问题

  • 什么是更好的解决方案,更加“反应”,我在这里缺少什么?
  • 完全使用被动方法是否有意义?

side effect我的意思是:

  

使用异步数据流进行编程

2 个答案:

答案 0 :(得分:0)

反应很好,我认为这种情况很完美。

我认为你真正想要做的就是确保你的每个操作员完全 1 。就像你说的那样,flatMap也在消除你的地理围栏。

尝试使用链中的onNext运算符进行删除。你要做什么检索它,它看起来像geofenceRepository.get(id),用运算符删除它,然后从locationProvider中删除它。也许是这样的:

geofenceRepository.get(id)
        .map(new Func1<Geofence, String>() {
            @Override
            public String call(Geofence geofence) {
                return geofence.getRequestId();
            }
        })
        .doOnNext(new Action1<String>){
          @Override
          public void call(final String geoFenceId) {
            geofenceRepository.delete(geofence.getId());
          }
        })
        .doOnNext(new Action1<String>() {
          @Override
          public void call(final String geoFenceId) {
                return locationProvider.removeGeofences(ids);
          }
        });

您可能真正想要做的是创建两个订阅者。这样,如果你想观察一个或两个的状态,你可以。您可以组合每个的状态。它取决于是否从存储库中删除并从提供程序中删除是独立的。

Observable<String> getFence = geofenceRepository.get(id)
        .map(new Func1<Geofence, String>() {
            @Override
            public String call(Geofence geofence) {
                return geofence.getRequestId();
            }
        });

        getFence.subscribe(new Action1<String>){
          @Override
          public void call(final String geoFenceId) {
            geofenceRepository.delete(geofence.getId());
          }
        });

        getFence.map(new Func1<String, Status>() {
          @Override
          public Status call(final String geoFenceId) {
                return locationProvider.removeGeofences(ids);
          }
        }).subscribe(new Action1<Status>(){
           @Override
           public void call(final Status status(){
              //Handle your status for each removal
           }
        });

答案 1 :(得分:0)

我没有发现您的方法存在任何问题,而且更具反应性意味着更多API使用/返回Observables。你可以在任何lambdas中产生副作用,但是当你改变一个值时要小心,因为如果涉及异步,同一个对象可能会在管道的不同阶段同时发生变异。通常,我们使用不可变或有效不可变值来避免此问题。没有必要拆分您的活动,因此建议的doOnNext分离是特定开发人员的偏好

如果您的geofenceRepository.delete的某个版本返回某种类型的Observable,则可以通过flatMapping覆盖它来更加反应:

get(id)
.flatMap(f -> geoFence.deleteAsync(f.getId()).map(v -> f.getRequestId()))
.toList()
.flatMap(...)
.subscribe(...)

在这里,deleteAsync将返回Observable<Void>,完成后将使用requestId恢复主序列。