取消订阅时清算资源

时间:2016-10-21 14:50:23

标签: java android rx-java

我在订阅取消订阅时执行某些逻辑时遇到了一些麻烦。我已经在这几个小时了,到目前为止我没有取得什么进展。这是我的代码的简化版本:

public class Command<E> {

    public CommandActionObservable execute() {
        final CommandAction<E> command = createCommand();

        final OnSubscribe<CommandAction<E>> onSubscribe = (subscriber) -> {

            /* Create a listener that handles notifications and register it.
             * The idea here is to push the command downstream so it can be re-executed
             */
            final Listener listener = (event) -> {
              subscriber.onNext(command);
            }
            registerListener(listener);

            /* This is where I'm having trouble. The unregister method
             * should be executed when the subscriber unsubscribed, 
             * but it never happens
             */
            subscriber.add(Subscriptions.create(() -> {
                unregisterListener(listener);
            }));

            // pass the initial command downstream
            subscriber.onNext(command);

            kickOffBackgroundAction();             
        }

        final Observable<CommandAction<E>> actionObservable = Observable.create(onSubscribe)
            .onBackpressureLatest()
            .observeOn(Shedulers.io())
            .onBackpressureLatest();
        return new CommandActionObservable((subscriber) -> {
            actionObservable.unsafeSubscribe(subscriber);
        })
    }

    public class CommandActionObservable extends Observable<CommandAction<E> {

        // default constructor omitted

        public Observable<E> toResult() {
            return lift((Operator) (subscriber) ->  {
                return new Subscriber<CommandAction<E>>() {
                    // delegate onCompleted and onError to subscriber

                    public void onNext(CommandAction<E> action) {
                        // execute the action and pass the result downstream
                        final E result = action.execute();
                        subscriber.onNext(result)
                    }
                } 
            }
        }

    }

}

我以通常的方式使用Command,将生成的订阅添加到CompositeSubscription并在onDestroy()中取消订阅。这是一个例子:

final Observable<SomeType> obs = new Command<SomeType>()
                                       .execute()
                                       .toResult();
subscription.add(obs.subscribe(// impl here));



public void onDestroy() {
    super.onDestroy();
    subscription.unsubscribe();
}

如上所述,我无法使取消订阅逻辑工作并取消注册侦听器,这会导致应用程序中的内存泄漏。如果我在doOnUnsubscribe()上调用obs它会被调用,所以我没有正确地解释,但是可能嵌套可观察量和提升会导致一些问题。

我很乐意对此发表意见。

1 个答案:

答案 0 :(得分:1)

事实证明这比我预想的要容易得多。

经过一番挖掘后,我能够自己拿出答案。只是发布给那些可能最终和我一样的人。

所以,正如我在我的问题中所提到的,如果我在我的doOnSubscribe()中添加了Activity动作,我会收到通知。接下来,我尝试在内部Observables上添加相同的操作,我在execute()方法中创建。他们没有被召唤。所以,我得出的结论是,在我的活动中的观察者和我在execute()中创建的可观察者之间的链条被破坏了。

流中唯一发生的事情是我在Operator中实施的自定义toResult()的应用。在Google搜索之后,我发现了这篇优秀的文章 - Pitfalls of Operator Implementation。我确实在我的操作员中制动了链条,上游的观察者没有收到取消订阅的通知。

在我做了作者建议之后,一切都很好。这是我需要做的:

lift((Operator) (subscriber) -> {
    // connect the upstream and downstream subscribers to keep the chain intact
    new Subscriber<CommandAction<E>>(subscriber) {
        // the implementation is the same
    }
}