使用RxJava和取消订阅在活动之间共享Observable

时间:2017-02-07 08:43:39

标签: android rx-java observable rx-android subject-observer

我正在尝试实现在我的应用程序Observable之间共享的计时器Activities。我正在一个Dagger单例类中进行实现,我在每个Presenter的每个Activity中注入。

我创建了一次Observable:

Observable.defer(() -> Observable.timer(milliseconds, TimeUnit.MILLISECONDS).map(t -> this::doSomethingCool()))
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .share();

我使用函数

从Presenter进行订阅
public Observable<Status> register(Callback callback) {

    PublishSubject<Status> subject = PublishSubject.create();
    subject.subscribe(status -> {},
            throwable -> L.LOGE(TAG, throwable.getMessage()),
            () -> callback.onStatusChanged(mBasketStatus));

    mObservable.subscribe(subject);
    basketCounterCallback.onStatusChanged(status));

    subject.doOnUnsubscribe(() -> L.LOGD(TAG, "Unsubcribed from subject!"));
    return subject.asObservable();
}

我将Subject作为Observable存储在每个演示者中,我打电话给:     obs.unsubscribeOn(AndroidSchedulers.mainThread()) 取消订阅(在onPause()方法中)。我还尝试使用调度程序Schedulers.immediate()

取消订阅

但是无论如何都会调用回调X次(其中X是我订阅定时器的所有Presenters),因此它不会取消订阅。此外,日志"Unsubcribed from subject!"未被调用。

如何从每个主题中正确取消订阅?

提前致谢

修改

由于评论而添加了更多实施细节:

这是我在SingletonStatusManager的成员中创建Observable并存储的部分(状态也是单例):

private Observable<BasketStatus> mObservable;
private Status mStatus;

public Observable<BasketStatus> start(long milliseconds, Status status, Callback callback) {

    if (mObservable == null) mObservable = createObservable(milliseconds, status);

    return register(callback);
}

private Observable<BasketStatus> createObservable(long milliseconds, Status status) {

    mStatus = status;

    return Observable.defer(() -> Observable.timer(milliseconds, TimeUnit.MILLISECONDS).map(t -> status.upgradeStatus()))
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .share();
}

public Observable<BasketStatus> register(Callback callback) {

    PublishSubject<Status> subject = PublishSubject.create();
    subject.subscribe(status -> {},
            throwable -> L.LOGE(TAG, throwable.getMessage()),
            () -> callback.onStatusChanged(mStatus));

    mObservable.subscribe(subject);
    callback.onStatusChanged(mStatus));

    subject.doOnUnsubscribe(() -> L.LOGD(TAG, "Unsubcribed from subject!"));
    return subject.asObservable();
}

从启动计时器的start(...)调用方法Presenter之后,我会从下一位演示者调用register(...)方法:

class Presenter implements Callback {

    private Observable<BasketStatus> mRegister;

    @Inject
    public Presenter(Status status, StatusManager statusManager) {
        mRegister = statusManager.start(20000, status, this);
    }

    // Method called from onPause()
    public void unregisterFromBasketStatus() {
         mRegister.unsubscribeOn(Schedulers.immediate());
    }
}

下一位主持人......

@Inject
public NextPresenter(StatusManager statusManager) {
    mBasketStatusManager.register(this);
}

1 个答案:

答案 0 :(得分:4)

正如我在评论中提到的,您没有得到<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body> <h1>Play game!</h1> <div id="gameboard"> <div class="pic-row1"> <img src="programming.jpeg" alt="jQuery code" style="width:180px; height:180px;" class="pictures" data-cardid="programming"> <img src="confusedoldman.jpeg" alt="Confused old man" style="width:180px; height:180px;" class="pictures" data-cardid="confusedoldman"> <img src="santabeatdown.jpeg" alt="Santa ready to rumble" style="width:180px; height:180px;" class="pictures" data-cardid="santabeatdown"> <img src="sparkles.jpeg" alt="Sparkling lights" style="width:180px; height:180px;" class="pictures" data-cardid="sparkles"> </div> <div class="pic-row2"> <img src="santabeatdown.jpeg" alt="Santa ready to rumble" style="width:180px; height:180px;" class="pictures" data-cardid="santabeatdown"> <img src="pizzalover.jpg" alt="Loving the pizza" style="width:180px; height:180px;" class="pictures" data-cardid="pizzalover"> <img src="fishbowling.jpg" alt="Fish jumping" style="width:180px; height:180px;" class="pictures" data-cardid="fishbowling"> <img src="monkeys.jpeg" alt="Monkeys" style="width:180px; height:180px;" class="pictures" data-cardid="monkeys"> </div> <div class="pic-row3"> <img src="fishbowling.jpg" alt="Fish jumping" style="width:180px; height:180px;" class="pictures" data-cardid="fishbowling"> <img src="confusedoldman.jpeg" alt="Confused old man" style="width:180px; height:180px;" class="pictures" data-cardid="confusedoldman"> <img src="sparkles.jpeg" alt="Sparkling lights" style="width:180px; height:180px;" class="pictures" data-cardid="sparkles"> <img src="redpanda.jpeg" alt="A red panda" style="width:180px; height:180px;" class="pictures" data-cardid="redpanda"> </div> <div class="pic-row4"> <img src="programming.jpeg" alt="jQuery code" style="width:180px; height:180px;" class="pictures" data-cardid="programming"> <img src="redpanda.jpeg" alt="A red panda" style="width:180px; height:180px;" class="pictures" data-cardid="redpanda"> <img src="monkeys.jpeg" alt="Monkeys" style="width:180px; height:180px;" class="pictures" data-cardid="monkeys"> <img src="pizzalover.jpg" alt="Loving the pizza" style="width:180px; height:180px;" class="pictures" data-cardid="pizzalover"> </div> </div> </body>运算符的行为。它不会取消订阅任何内容,而是告诉每个订阅者,当 取消订阅时,它应该在哪里执行其工作 。它也没有意义,因为你不是从Observable取消订阅,而是从 订阅 取消订阅,它代表观察者和流本身之间的连接。

回到你的问题。您的代码现在的设计方式,您返回的主题完全没用。您在注册方法中订阅了可观察的计时器,但是您将这些通知转发给之后从未订阅过的主题。如果您真的需要它们,在我们没有看到的代码的某些部分中,您需要存储unsubscribeOn方法的结果,该方法是subscribe()对象并调用Subscription当你需要时(在unsubscribe()我推测)。

但代码中存在更多问题。例如:

unregisterFromBasketStatus

在第一行中,您不会将该操作的结果存储在任何位置。由于Observable是不可变结构,因此每个运算符都会创建一个新流,该流接收来自前一个的通知。由此可见,当您在第二行返回subject.doOnUnsubscribe(() -> L.LOGD(TAG, "Unsubcribed from subject!")); return subject.asObservable(); 时,您不会从第一行返回已修改的observable,而是返回旧的未修改的observable。要解决此问题,只需将subject.asObservable()变量替换为结果:subject

其次,使用流的原因之一是完全取代回调。当然,它会起作用,但是你正在减轻Rx为代码库带来的诸多好处。然而,它的可读性要差得多,任何人在你诅咒地狱之后都必须处理你的代码以至于他实际上可能成功:-))我明白,Rx从一开始就很难学习,但是试试看尽量避免这种情况。