4
\$\begingroup\$

In my Android app I have a Service that is periodically polling a server for a music playlist XML. For certain occasions I also want to trigger a reload manually.

I am using Retrofit for the server communication and my Service exposes an Observable<Playlist> to which some other components of the app can subscribe. At the moment there are two such subscribers: One Fragment that contains the playback controls and one other Service that manages the actual audio streaming as well as the updates to the Notifications.

Now, I want all Subscribers to receive any new playlist info as soon as it becomes available. In particular this means that if I trigger a reload manually from the Fragment, the Service should also immediately receive the server response.

No matter how I turn it, all my solutions need a Subject. Here's the one I like best:

private Observable<MusicInfoResponse> mReloadingObservable;
private PublishSubject<Long> mManualRefreshesSubject = PublishSubject.<Long>create();

private void setupObservable() {

    Observable<Long> timer = Observable.timer(0, 15, TimeUnit.SECONDS);

    Observable<Long> pulses = Observable.merge(timer, mManualRefreshesSubject);

    mReloadingObservable = pulses
        .flatMap(new Func1<Long, Observable<MusicInfoResponse>>() {

            @Override
            public Observable<MusicInfoResponse> call(Long aLong) {
                Log.d(LOG_TAG, "reloading music info XML");
                return reloadMusicInfo();
            }
        })
        .share();
}

public Observable<MusicInfoResponse> subscribeToMusicInfo() {
    return mReloadingObservable;
}

public void triggerManualRefresh() {
    mManualRefreshesSubject.onNext(1l);
}

Since, it seems to me, one should generally avoid Subjects and try to use only normal Observables instead my question is: Is there any way to this that does not need Subjects? Is this a case where using Subjects is the way to go?

And also: What are the main drawbacks of Subjects in general?

\$\endgroup\$
6
\$\begingroup\$

There is no rule like

one should generally avoid Subjects

You should just be careful around them, like you have. Just as a rule of thumb, keep Subjects private (inside your class), and if you want the outside world to be able to subscribe to it, just call subject.asObservable.

As for your code, you can perform the setupObservable() inside an obervable.onSubscribe() so that you have a cold observable and not a hot one.

If you really have to remove the Subject, you can do a Observable.create(subsriber -> ...). This subscriber variable would be the replacement for your mManualRefreshesSubject.

Frankly, there is not much difference between either pattern. The only thing you should do is check whether the subject.isUnsubscribed() / subscriber.isSubscribed. One benifit of using a subscriber is that you make sure to do stuff onSubscribe and not before.

\$\endgroup\$
  • \$\begingroup\$ It just no occurred to me that I'd never accepted this answer until now... Sorry! \$\endgroup\$ – david.mihola Feb 4 '16 at 8:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.