java rx中Observable.defer和Observable.create之间的区别

时间:2016-03-30 15:55:34

标签: java reactivex

有人可以解释一下defercreateObservable方法之间的区别吗?我无法理解何时应该使用defer,何时应该使用create ..

参考文献:

推迟:http://reactivex.io/documentation/operators/defer.html

创建:http://reactivex.io/documentation/operators/create.html

谢谢

3 个答案:

答案 0 :(得分:18)

所以区别似乎是:当你有一些创建/返回一个observable的东西时,defer是好的,但是你不希望它在订阅之前发生。

当您需要手动包装异步进程并创建可观察对象时,

create很好。该创建推迟到订阅。

换句话说:

defer是一个允许可观察序列的延迟组合的运算符。

create是可观察序列的自定义实现(其中创建被推迟到订阅之前)。

因此,如果您有可能使用just从某些结果/值创建Observable,或者您有一个返回Observable请求的网络API层,但是你不希望这个请求在订阅之前启动。 defer会对这些情况有所帮助。

如果您的网络API层没有为请求返回Observable,但您需要Observable接口,则可以使用{{ 1}}。在订阅之前,仍然不会创建create序列。如果您希望该网络呼叫无论订阅如何开始,那么您将使用不同的机制,例如Observable,可能会重播。

答案 1 :(得分:12)

create(...)实际上会立即创建Observable。

    public final static <T> Observable<T> create(OnSubscribe<T> f) {
        return new Observable<T>(hook.onCreate(f));
    }

defer(...)接受返回Observable(Subject,etc ...)的Factory函数,用OnSubscribeDefer包装它,并仅在订阅者订阅时创建Observable,为每个订阅者创建新的Observable。

public final static <T> Observable<T> defer(Func0<Observable<T>> observableFactory) {
    return create(new OnSubscribeDefer<T>(observableFactory));
}

查看更多详情here

答案 2 :(得分:0)

以上面的例子为例,另外一个很好的答案。

假设您有一个基于其内部状态返回Observable的类(以类似语言的伪Javascript编写,但适用于所有ReactiveX实现)

class DownloadManager {

  var uuid = nil  // this only gets set during runtime...say when a user performs a certain action

  // fetches some data from the server.
  func get() -> Observable<Data> {
    if uuid == nil {
      return .error(new DownloadUuidEmptyError())
    }
 
    return network.download(uuid, ...) // do something with the non nil uuid
  }
}

这样编写,可能会调用该方法,并且在实际评估该可观察对象之前将其传递出去,并且在方法调用时可能不会出现uuid,但在订阅该Observable时会出现uuid,从而产生错误

let observable = manager.get()

// ... at some point, uuid is assigned to
// then we subscribe to our observable ...

observable.subscribe(...).disposedBy(bag) // errors!

在这种情况下,可以使用defer来确保在订阅之前不进行评估(例如,对uuid的评估)。

  // fetches some data from the server.
  func get() -> Observable<Data> {
    return Observable.defer {
      if uuid == nil {
        return .error(new DownloadUuidEmptyError())
      }

      return network.download(uuid, ...) // do something with the non nil uuid
    }
  }

现在,以上示例将不再出错。也许更大的目标是确保您的代码永远不会达到这种状态,但是有时这是不切实际的。这种模式对我来说很方便。