我正在为我的应用开发网络。所以我决定试试Square的Retrofit。我看到它们支持简单的回调

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

和RxJava的Observable

@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

乍一看,两者都非常相似,但当它实现时,它就变得有趣了……

而简单的回调实现看起来类似于:

api.getUserPhoto(photoId, new Callback<Photo>() {
    @Override
    public void onSuccess() {
    }
});

这是非常简单直接的。而使用Observable,它很快就会变得冗长且相当复杂。

public Observable<Photo> getUserPhoto(final int photoId) {
    return Observable.create(new Observable.OnSubscribeFunc<Photo>() {
        @Override
        public Subscription onSubscribe(Observer<? super Photo> observer) {
            try {
                observer.onNext(api.getUserPhoto(photoId));
                observer.onCompleted();
            } catch (Exception e) {
                observer.onError(e);
            }

            return Subscriptions.empty();
        }
    }).subscribeOn(Schedulers.threadPoolForIO());
}

但事实并非如此。你仍然需要做这样的事情:

Observable.from(photoIdArray)
        .mapMany(new Func1<String, Observable<Photo>>() {
            @Override
            public Observable<Photo> call(Integer s) {
                return getUserPhoto(s);
            }
        })
        .subscribeOn(Schedulers.threadPoolForIO())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<Photo>() {
            @Override
            public void call(Photo photo) {
                //save photo?
            }
        });

我是不是遗漏了什么?或者在这种情况下使用可观察对象是错误的? 什么时候会/应该更喜欢Observable而不是简单的回调?

更新

使用改造比上面的例子简单得多,就像@Niels在他的回答中或Jake Wharton的例子项目U2020中所展示的那样。但本质上的问题是不变的——什么时候应该使用一种方式或另一种方式?


当前回答

使用rxjava,你可以用更少的代码做更多的事情。

让我们假设你想在你的应用中实现即时搜索。 通过回调,你担心取消订阅前一个请求并订阅新请求,自己处理方向更改…我认为这是大量的代码和太啰嗦。

用rxjava非常简单。

public class PhotoModel{
  BehaviorSubject<Observable<Photo>> subject = BehaviorSubject.create(...);

  public void setUserId(String id){
   subject.onNext(Api.getUserPhoto(photoId));
  }

  public Observable<Photo> subscribeToPhoto(){
    return Observable.switchOnNext(subject);
  }
}

如果你想实现即时搜索,你只需要监听TextChangeListener并调用photommodel . setuserid (EditText.getText());

在Fragment或activity的onCreate方法中,你订阅了返回photomode . subscribetophoto()的Observable,它会返回一个总是发出由最新的Observable(request)发出的项的Observable。

AndroidObservable.bindFragment(this, photoModel.subscribeToPhoto())
                 .subscribe(new Action1<Photo>(Photo photo){
      //Here you always receive the response of the latest query to the server.
                  });

此外,如果photommodel是一个单例,例如,您不需要担心方向更改,因为不管您何时订阅,BehaviorSubject都会发出最后一个服务器响应。

通过这几行代码,我们实现了即时搜索和处理方向更改。 你认为你可以用更少的代码实现回调吗?我对此表示怀疑。

其他回答

Observable的东西已经在Retrofit中完成了,所以代码可以是这样的:

api.getUserPhoto(photoId)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Photo>() {
         @Override
            public void call(Photo photo) {
                //save photo?
            }
     });

在getUserPhoto()的情况下,RxJava的优势不是很大。 但让我们再举一个例子,当你为一个用户获取所有照片时,但只有当图像是PNG时,你不能访问JSON来在服务器端进行过滤。

api.getUserPhotos(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<List<Photo>, Observable<Photo>>() {
    @Override
    public Observable<Photo> call(List<Photo> photos) {
         return Observable.from(photos);
    }
})
.filter(new Func1<Photo, Boolean>() {
    @Override
    public Boolean call(Photo photo) {
         return photo.isPNG();
    }
})
.subscribe(
    new Action1<Photo>() {
    @Override
        public void call(Photo photo) {
            // on main thread; callback for each photo, add them to a list or something.
            list.add(photo)
        }
    }, 
    new Action1<Throwable>() {
    @Override
        public void call(Throwable throwable) {
            // on main thread; something went wrong
            System.out.println("Error! " + throwable);
        }
    }, 
    new Action0() {
        @Override
        public void call() {
            // on main thread; all photo's loaded, time to show the list or something.
        }
    });

现在JSON返回Photo的列表。我们将把它们平面映射到单独的项目。通过这样做,我们将能够使用过滤器方法来忽略非PNG的照片。之后,我们将订阅,并为每张照片获取一个回调,一个errorHandler,以及当所有行都完成时的回调。

TLDR 这里的点是;回调只返回成功和失败的回调;RxJava Observable允许你做映射,减少,过滤和更多的事情。

看起来你在重新发明轮子,你所做的已经在改造中实现了。

举个例子,你可以看看retrofit的RestAdapterTest.java,在那里他们定义了一个接口,将Observable作为返回类型,然后使用它。

我们通常遵循以下逻辑:

如果它是一个简单的单响应调用,那么Callback或Future更好。 如果一个调用有多个响应(流),或者不同调用之间有复杂的交互(参见@Niels的回答),那么Observables更好。

使用rxjava,你可以用更少的代码做更多的事情。

让我们假设你想在你的应用中实现即时搜索。 通过回调,你担心取消订阅前一个请求并订阅新请求,自己处理方向更改…我认为这是大量的代码和太啰嗦。

用rxjava非常简单。

public class PhotoModel{
  BehaviorSubject<Observable<Photo>> subject = BehaviorSubject.create(...);

  public void setUserId(String id){
   subject.onNext(Api.getUserPhoto(photoId));
  }

  public Observable<Photo> subscribeToPhoto(){
    return Observable.switchOnNext(subject);
  }
}

如果你想实现即时搜索,你只需要监听TextChangeListener并调用photommodel . setuserid (EditText.getText());

在Fragment或activity的onCreate方法中,你订阅了返回photomode . subscribetophoto()的Observable,它会返回一个总是发出由最新的Observable(request)发出的项的Observable。

AndroidObservable.bindFragment(this, photoModel.subscribeToPhoto())
                 .subscribe(new Action1<Photo>(Photo photo){
      //Here you always receive the response of the latest query to the server.
                  });

此外,如果photommodel是一个单例,例如,您不需要担心方向更改,因为不管您何时订阅,BehaviorSubject都会发出最后一个服务器响应。

通过这几行代码,我们实现了即时搜索和处理方向更改。 你认为你可以用更少的代码实现回调吗?我对此表示怀疑。