0
votes

Is it acceptable to create Rx Observables in custom Application subclass. Reason for doing is, I can create BehaviorSubject inside the Application and will ask for changes every 10 minutes from Server, every Activity or Fragment which subscribes to this Observable will get only last state of changes.

Question is whether this architecture could be considered safe in terms of application lifecycle handling and easy to use?

class CustomApplication extends Application {
   ...

   BehaviorSubject<Friends> mFriends = new BehaviorSubject<Friends>;
   public void createObservables() {
      Observable.create(new Observable.OnSubscribe<Friends>() {
         public void call(Subscriber<?> s) {
            while(true) {
               mFriends.onNext("randomFriendN");
               sleep(10sec);
            }
         }
      })
      .subscribeOn(Schedulers.newThread())
      .subscribe(new Observer<List<NewsCategory>>() {
         public void onNext(Friends f) { //empty }
      });
   }
   public BehaviorSubject<Friends> getFriends() {
      return mFriends;
   }
}

UPDATE: Everytime when new activity created and it wants to get data it can get it ApplicationContext's BehaviorSubject then subscribe to it, and Subject will emit last emitted value; Why I want to do like this? E.g. Lets say you have news items, you fetched news feed and you want to start background task which fetches news item full content, in that case I can start fetching data while you are scrolling news list, and when you click detailed activity, we can show it from already fetched, or just download it.

1
Could you perhaps provide some pseudo code to clear up any ambiguity? - nhaarman
provided with kind of pseudo code, thanks for advice - user1831986
Just a improvement tips: BehaviorSubject is also a Observer. You can subscribe(BehaviorSubject) directly. - zsxwing
To me this is not safe. Even if you unsubscribe everything from the subject, the Observable sending message down the subject would never get garbage collected. If you call createObservables twice, both observables will be around forever (Specially because this is in Application). - Akito

1 Answers

2
votes

I think this is perfectly safe as long as createObservables() is only called once during application initialization. A few suggested changes...

I wouldn't expose the BehaviorSubject part of mFriends in the returned value from getFriends(). That way callers of getFriends() will not be tempted to call onNext(). Change it to:

public Observable<Friends> getFriends() {
    return mFriends;
}

If you want to be super safe use .asObservable() and callers will not even be able to cast the return value back to a BehaviorSubject.

public Observable<Friends> getFriends() {
    return mFriends.asObservable();
}

I would also update your createObservable() method to call the BehaviorSubject onNext() from the subscribe callback. Here is your code slightly modified to use NewsItems.

BehaviorSubject<List<NewsItem>> mNewsItemSubject = BehaviorSubject.create();

void createObservables() {
    Observable
            .timer(10, 10, TimeUnit.SECONDS, Schedulers.newThread())
            .flatMap(new Func1<Long, Observable<List<NewsItem>>>() {
                @Override
                public Observable<List<NewsItem>> call(Long aLong) {
                    // Normally you would create a network API that returns Observable<NewsItem>.
                    // For now just pretend this returned Observable makes an Observable
                    // network request.
                    return Observable.just(
                            Arrays.asList(
                                    new NewsItem("fakeNewsItem"),
                                    new NewsItem("fakeNewsItem1")
                            )
                    );
                }
            })
            .subscribe(new Action1<List<NewsItem>>() {
                @Override
                public void call(List<NewsItem> newsItems) {
                    mNewsItemSubject.onNext(newsItems);
                }
            });
}

public Observable<List<NewsItem>> observeNewsItems() {
    return mNewsItemSubject;
}

Your Android Activities can then call ((CustomApplication)getApplication()).observeNewsItems() to get the latest news items and any updates while the Activity is visible.

final Observable<List<NewsItem>> newsItemsObservable = 
    ((CustomApplication) getApplication()).observeNewsItems();

newsItemsObservable
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<List<NewsItem>>() {
            @Override
            public void onCompleted() {
                // All done.
            }

            @Override
            public void onError(Throwable e) {
                // Notify user of error (maybe)
            }

            @Override
            public void onNext(List<NewsItem> newsItems) {
                // Update the UI with newsItems.
            }
        });