Recipes in RxJava for
Android
Sasa Sekulic
co-author of the Manning book “Grokking Rx”(with Fabrizio Chignoli and Ivan Morgillo); developer of the
UN-WFP ShareTheMeal app; cofounder of Alter Ego Solutions
@sasa_sekulic | www.alterego.solutions | Grokking Rx MEAP: http://bit.ly/grokking-rx
UN World Food Programme - ShareTheMeal
We provide food to schoolchildren in need – over 5.000.000 meals shared!
It costs only €0.40 to feed one child for a day. www.sharethemeal.org
Google Play Best of 2015 & Editor's Choice, SXSW 2015 Innovation Award
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Basics of RxJava
Observer
Observable
Subscription
Subscriber (Observer & Subscription)
Subject (Observer & Observable)
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Observable creation from any object
just(), from() – simple, executed immediately upon creation
create() – executed upon subscription but need to take care of contract calls
defer()/fromCallable() – simple, but executed upon subscription
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Observable creation –example 1: too simple
just(), from() – simple, executed immediately upon creation
public Observable<Boolean> exampleBlocking() {
SharedPreferences prefs = context.getSharedPreferences("prefs",
Context.MODE_PRIVATE);
return Observable.just(prefs.getBoolean("boolean", false));
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Observable creation –example 2: too complicated
create() – executed upon subscription but need to take care of contract calls
public Observable<Boolean> exampleTooComplicated() {
SharedPreferences prefs = context.getSharedPreferences("prefs",
Context.MODE_PRIVATE);
}
return Observable.create(new Observable.OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
if (subscriber.isUnsubscribed()) {
return;
}
subscriber.onNext(prefs.getBoolean("boolean", false));
if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}
});
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Observable creation –create() isn't as easy as it looks
think about the unsubscription/backpressure chain
Observable.create(s -> {
int i = 0;
while (true) {
s.onNext(i++);
}
}).subscribe(System.out::println);
for list of many more other problems:
http://akarnokd.blogspot.hu/2015/05/pitfalls-of-operator-implementations.html
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Observable creation –example 3: just right
defer() – simple, but executed upon subscription
fromCallable() – the same, for methods that return values
public Observable<Boolean> exampleJustRight() {
SharedPreferences prefs = context.getSharedPreferences("prefs",
Context.MODE_PRIVATE);
return Observable.defer(new Func0<Observable<Boolean>>() {
@Override
public Observable<Boolean> call() {
return Observable.just(prefs.getBoolean("boolean", false));
}
});
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Observable creation –special case of from()
from(Future<? extends T>) – blocking, cannot unsubscribe (but you can
specify timeout or Scheduler)
from(Iterable<? extends T>), from(T[]) – convert Iterable/array event into
events from Iterable/array
List<Boolean> list = new ArrayList<>();
Observable.just(list).subscribe(new Observer<List<Boolean>>(){ ... }
//takes List<Boolean>, emits List<Boolean>
Observable.from(list).subscribe(new Observer<Boolean>(){ ... }
//takes List<Boolean>, emits Boolean items from the list
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Observable creation –forEach() equivalent ops
List<Boolean> list = new ArrayList<>();
Observable.from(list)
.map(aBoolean -> !aBoolean) //returns value
.flatMap(aBoolean -> Observable.just(aBoolean.hashCode())
//returns observable<value>
.toList() //or .toSortedList()
.subscribe(new Observer<List<Integer>>() { ...
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects
they're Hot observables – the values are generated independently of existence of subscribers
use them to send values to Observers outside creation block
enable you to have communication between the Observer and Observable-value generator
access onNext(), onError() and onCompleted() whenever you want
single-threaded by default, don't mix threads when calling onXXX()!
for thread safety, wrap them in a SerializedSubject() or call Subject.toSerialized().onXXX()
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects - types
PublishSubject
– doesn’t store any states, just sends what it receives while subscribed (you miss anything in between)
– epitome of Hot observable
BehaviourSubject
– remembers the last value
– emptied after onCompleted()/onError()
- can be initialized with a value
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects – types, cont'd
AsyncSubject
– remembers the last value
– after onCompleted() subscribers receive the last value and the onCompleted() event
– after onError() subscribers receive just the onError() event
ReplaySubject
– remembers everything but can be limited (create(int bufferCapacity),
createWithSize(int size), createWithTime(long time, TimeUnit unit, final
Scheduler scheduler), createWithTimeAndSize(long time, TimeUnit unit, int
size, final Scheduler scheduler))
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects – music player example UX
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects – music player example states
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects – music player example Observer
public class MusicPlayer {
public enum PLAYER_STATE {STOPPED, PLAYING}
Observer<PLAYER_STATE> playerObserver =
new Observer<PLAYER_STATE>() {
@Override
public void onNext(PLAYER_STATE state) {
currentPlayerState = state;
if (state == PLAYER_STATE.PLAYING) {
startSong();
showPauseButton();
} else if (state == PLAYER_STATE.STOPPED) {
stopSong();
showPlayButton();
}
}
}
};
...
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects – music player example Subject
public class MusicPlayer {
PLAYER_STATE currentPlayerState = PLAYER_STATE.STOPPED;
BehaviorSubject<PLAYER_STATE> playerStateSubject =
BehaviorSubject.create(currentPlayerState);
public MusicPlayer() {
playerStateSubject.subscribe(playerObserver);
}
private void pressButton() {
if (currentPlayerState == PLAYER_STATE.PLAYING) {
playerStateSubject.onNext(PLAYER_STATE.STOPPED);
} else if (currentPlayerState == PLAYER_STATE.STOPPED) {
playerStateSubject.onNext(PLAYER_STATE.PLAYING);
}
}
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subjects – music player example optimization
We don't need currentPlayerState, just use playerStateSubject.getValue()
Don't expose Subject to others: when offering them for subscribing, use getObservable()
public Observable<PLAYER_STATE> getPlayerStateObservable() {
return playerStateSubject.asObservable();
}
Use Subscription to control Observer lifecycle!
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subscription
Subscription is a relationship between the Observer and the Observable
public MusicPlayer() {
Subscription stateSub = playerStateSubject.subscribe(playerObserver);
}
Subscription is returned by the subscribe()
public MusicPlayer() {
Subscription stateSub = playerStateSubject //Observable
.filter(state -> state == PLAYING) //Observable
.map(state -> someMethod())
//Observable
.subscribe(playerObserver);
//Subscription
}
Very simple: isUnsubscribed(), unsubscribe()
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subscription – usage
To control the lifecycle and/or release the resources, call it in onPause()/onStop()/onDestroy():
@Override
protected void onDestroy() {
super.onDestroy();
if (mPlayerSubscription != null &&
!mPlayerSubscription.isUnsubscribed()) {
mPlayerSubscription.unsubscribe();
}
}
If you don't want to do null checks, initialize the subscription:
Subscription mPlayerSubscription = Subscriptions.unsubscribed();
//or Subscriptions.empty();
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subscription – usage, cont'd
To prevent multiple executions/subscriptions:
public MusicPlayer() {
if (mPlayerSubscription == null ||
mPlayerSubscription.isUnsubscribed()) {
mPlayerSubscription =
playerStateSubject.subscribe(playerObserver);
}
}
Important: unsubscribing has no impact on the observable or other subscriptions!
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
CompositeSubscription – grouping Subscriptions
When you need to control multiple subscriptions at the same time:
CompositeSubscription activitySubscriptions = new CompositeSubscription();
@Override
protected void onCreate() {
mPlayerSub = playerStateSubject.subscribe(playerObserver);
mPlayerSub2 = playerStateSubject.subscribe(playerObserver2);
activitySubscriptions = new CompositeSubscriptions(mPlayerSub,
mPlayerSub2);
}
@Override
protected void onResume() {
mPlayerSub3 = playerStateSubject.subscribe(playerObserver3);
activitySubscriptions.add(mPlayerSub3);
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
CompositeSubscription – grouping Subscriptions
(cont'd)
When you need to control multiple subscriptions at the same time: removing with remove(), unsubscribing all with
unsubscribe(), and clear() unsubscribes all and removes them from the CompositeSubscription:
@Override
protected void onPause() {
mPlayerSub3 = playerStateSubject.subscribe(playerObserver3);
activitySubscriptions.remove(mPlayerSub3);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (activitySubscriptions.hasSubscriptions() &&
!activitySubscriptions.isUnsubscribed()) {
activitySubscriptions.unsubscribe();
}
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subscription –control the lifecycle
Manually, on the Activity or Fragment level – create when you want, unsubscribe in
onPause()/onStop()/onDestroy()
Automatically, on the Activity or Fragment level – use https://github.com/trello/RxLifecycle
public class MainActivity extends RxAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
Observable.interval(1, TimeUnit.SECONDS)
.compose(this.<Long>bindUntilEvent(ActivityEvent.PAUSE))
//binds to onPause()
.subscribe(onCreateObserver);
}
}
.compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY))
//binds to onDestroy()
.compose(this.<Long>bindToLifecycle()) //binds automatically to opposite
method (if called from onResume() it will be bound to onPause()
One very important note: RxLifecycle doesn't call unsubscribe() but calls onCompleted() instead!
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subscription – control the lifecycle (global)
on the global, Application level – create when you want, and unsubscribe? Never,
so do the transactions atomically, close the observables and unsubscribe from
activities/fragments:
Manually
public class SplashActivity extends AppCompatActivity {
Subscription mUserSubscription = Subscriptions.empty();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
mUserManager.getUserObservable()
.subscribe(user -> continue(),
throwable -> showError(throwable));
}
@Override
protected void onDestroy() {
if (!mUserSubscription.isUnsubscribed())
mUserSubscription.unsubscribe();
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Subscription – control the lifecycle (global, cont'd)
public UserManager () {
//from() will automatically call onCompleted() so no pending references
Observable.from(loadUserFromSavedPreferences())
.subscribe(user -> mUserSubject.onNext(user),
throwable -> mUserSubject.onError(throwable));
}
Observable<User> getUserObservable() {
return mUserSubject.asObservable();
}
}
There's no automated way to manage lifecycle on the global level!
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Architecture example (bound to App context)
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Manager example (bound to App context)
loads a configuration, then loads a saved user, and propagates it:
public UserManager () {
public UserManager() {
mConfigurationManager.getCurrentConfigObservable()
.flatMap(config -> loadUserFromSavedPreferences())
.subscribe(user -> mUserSubject.onNext(user),
throwable -> mUserSubject.onError(throwable));
}
Observable<User> getUserObservable() {
return mUserSubject.asObservable();
}
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Manager example - error handling
sending onError() closes the subscription and no more events are sent!
onError() handles ALL errors in the chain!
to prevent this, use error handling methods:
– onErrorReturn() - use other value
– onErrorResumeNext() - use other observable
– onExceptionResumeNext() - handles Exceptions but not Throwables
mConfigurationManager.getCurrentConfigObservable()
.onErrorReturn(config -> Config.Empty)
.flatMap(config -> loadUserFromSavedPreferences())
.onErrorReturn(user -> User.Empty)
.subscribe(user -> mUserSubject.onNext(user);
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Manager example - splitting subscriptions
the whole of the chain is an Observable until the subscribe()
if you don’t use error management (onErrorReturn()/onErrorResumeNext()…), all subscriptions have to have
onError()– but that is always a good idea!!!
Observable<Config) configObservable =
mConfigurationManager.getCurrentConfigObservable()
.onErrorReturn(config -> Config.Empty);
Subscription configValidSub = configObservable
.filter(config -> config != null && config != Config.Empty)
.flatMap(config -> loadUserFromSavedPreferences())
.onErrorReturn(user -> User.Empty)
.subscribe(user -> mUserSubject.onNext(user));
Subscription configInvalidSub = configObservable
.filter(config -> config == null || config == Config.Empty)
.subscribe(config -> Log.d("App", "config empty!");
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Manager example - reusing observable chains
if you have a part of the chain that repeats itself – extract it in a Transformer<T, R> ()
Subscription configValidUserValidSub = configObservable
.filter(config -> config != null && config != Config.Empty)
.flatMap(config -> loadUserFromSavedPreferences())
.onErrorReturn(user -> User.Empty)
.filter(user -> user != User.Empty)
.subscribe(user -> mUserSubject.onNext(user));
Subscription configValidUserInalidSub = configObservable
.filter(config -> config != null && config != Config.Empty)
.flatMap(config -> loadUserFromSavedPreferences())
.onErrorReturn(user -> User.Empty)
.filter(user -> user == User.Empty)
.subscribe(user -> Log.d("APP", "user empty!");
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Manager example - reusing observable chains (cont'd)
Observable.Transformer<Config, User> convertConfigToUser() {
return new Observable.Transformer<Config, User>() {
@Override
public Observable<User> call(Observable<Config> configObservable) {
return configObservable
.filter(config -> config != null && config != Config.Empty)
.flatMap(config -> loadUserFromSavedPreferences())
.onErrorReturn(user -> User.Empty);
}
};
}
Subscription configValidUserValidSub = configObservable
.compose(convertConfigToUser())
.filter(user -> user != User.Empty)
.subscribe(user -> mUserSubject.onNext(user));
Subscription configValidUserInalidSub = configObservable
.compose(convertConfigToUser())
.filter(user -> user == User.Empty)
.subscribe(user -> Log.d("APP", "user empty!");
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Manager example - multithreading
RxJava is asynchronous by default, but not multithreaded by default!
use explicit methods to change the thread:
subscribeOn() – it changes the upstream thread (until that point)
observeOn() – it changes the downstream thread (after that point)
Observable.Transformer<Config, User> convertConfigToUser() {
return new Observable.Transformer<Config, User>() {
@Override
public Observable<User> call(Observable<Config> configObservable) {
return configObservable
.filter(config -> config != null && config != Config.Empty)
.flatMap(config -> loadUserFromSavedPreferences())
.onErrorReturn(user -> User.Empty)
.subscribeOn(Schedulers.io()) //everything up to this uses io() thread
.observeOn(AndroidSchedulers.mainThread()); // everything after this
// uses UI thread
}
};
}
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Multithreading – subscribeOn vs observeOn
subscribeOn() – it changes the upstream thread (until that point)
observeOn() – it changes the downstream thread (after that point)
Observable.fromCallable(()->
doSomething1(); //executed on IO thread
//if there's no subscribeOn(), execs on calling thread
)
.subscribeOn(Schedulers.io())
.filter(something -> doSomething2())
//subscribe call AND everything up to this uses io() thread
.observeOn(Schedulers.computation()); //changes thread to computation!
.flatMap(something -> doSomething3())
.onErrorReturn(user -> User.Empty)
.subscribeOn(Schedulers.computation()) //doesn't matter!!! wasteful!
.observeOn(AndroidSchedulers.mainThread()) //switches to UI thread
.subscribe(result -> doSomething4());
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Manager example - multithreading (cont'd)
RxJava Scheduler:
computation() – bound (limited by CPU cores)
io() - unbound
immediate() – executes immediately on current thread
trampoline() – executes after finishing, on current thread
newThread() – creates new thread
from(Executor) – use custom executor
test() – uses TestScheduler with manual scheduling controls
rxandroid library: AndroidScheduler.mainThread()
Multithreading is hard, RxJava makes it easier – but it's still not easy!
do not specify the thread unless you really need to
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
Further reading/watching
https://github.com/ReactiveX/RxJava
RxJava Single discussion: https://github.com/ReactiveX/RxJava/issues/1594
RxJava Subscriber discussion: https://github.com/ReactiveX/RxJava/issues/792
New viewbinding library using RxJava: https://github.com/alter-ego/androidbound
ReactiveX homepage: http://reactivex.io/
Interactive marble diagrams for operators: http://www.rxmarbles.com/
Ben Christensen's talks: https://speakerdeck.com/benjchristensen/
David Karnok's Advanced RxJava blog: http://akarnokd.blogspot.hu/
Grokking Rx MEAP: http://bit.ly/grokking-rx
Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic
© Copyright 2026 Paperzz