Slide 1

Slide 1 text

Reactive Extensions:
 Beyond the Basics Dan Lew April 11, 2015

Slide 2

Slide 2 text

Composition using compose()

Slide 3

Slide 3 text

Operator Reuse • Problem: Duplicated code Observable.just("...Some long running operation...")
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(System.out::println);

Slide 4

Slide 4 text

compose() • compose() Observable.just("...Some long running operation...")
 .compose(applySchedulers())
 .subscribe(System.out::println); • Transformer Observable.Transformer applySchedulers() {
 return observable -> observable.subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread());
 }

Slide 5

Slide 5 text

Lift() me up Custom Operators

Slide 6

Slide 6 text

Custom Operators • Reactive extensions don’t cover everything

Slide 7

Slide 7 text

Contrived Example Observable.interval(100, TimeUnit.MILLISECONDS)
 .takeUntil(Observable.timer(1, TimeUnit.SECONDS))
 .subscribe(
 i -> System.out.println("onNext!"),
 e -> System.out.println("onError!"),
 () -> System.out.println("onComplete!")
 );

Slide 8

Slide 8 text

Contrived Example Observable.interval(100, TimeUnit.MILLISECONDS)
 .takeUntil(Observable.timer(1, TimeUnit.SECONDS))
 .subscribe(
 i -> System.out.println("onNext!"),
 e -> System.out.println("onError!"),
 () -> System.out.println("onComplete!")
 );

Slide 9

Slide 9 text

Contrived Example Observable.interval(100, TimeUnit.MILLISECONDS)
 .takeUntil(Observable.timer(1, TimeUnit.SECONDS))
 .subscribe(
 i -> System.out.println("onNext!"),
 e -> System.out.println("onError!"),
 () -> System.out.println("onComplete!")
 );

Slide 10

Slide 10 text

Contrived Example Observable.interval(100, TimeUnit.MILLISECONDS)
 .lift(new OperatorSubscribeUntil<>(Observable.timer(1, TimeUnit.SECONDS)))
 .subscribe(
 i -> System.out.println("onNext!"),
 e -> System.out.println("onError!"),
 () -> System.out.println("onComplete!")
 );

Slide 11

Slide 11 text

Contrived Example Observable.interval(100, TimeUnit.MILLISECONDS)
 .lift(new OperatorSubscribeUntil<>(Observable.timer(1, TimeUnit.SECONDS)))
 .subscribe(
 i -> System.out.println("onNext!"),
 e -> System.out.println("onError!"),
 () -> System.out.println("onComplete!")
 );

Slide 12

Slide 12 text

final class OperatorSubscribeUntil implements Observable.Operator {
 private final Observable other;
 
 public OperatorSubscribeUntil(final Observable other) {
 this.other = other;
 }
 
 @Override
 public Subscriber call(final Subscriber child) {
 final Subscriber parent = new SerializedSubscriber(child);
 
 other.unsafeSubscribe(new Subscriber(child) {
 @Override
 public void onCompleted() {
 parent.unsubscribe();
 }
 
 @Override
 public void onError(Throwable e) {
 parent.onError(e);
 }
 
 @Override
 public void onNext(R t) {
 parent.unsubscribe();
 }
 });
 
 return parent;
 }
 }

Slide 13

Slide 13 text

Custom Operators • Avoid custom Operators if possible • Obey the Observable contract • Plenty of samples in core library

Slide 14

Slide 14 text

Subscriptions Avoid being a hoarder

Slide 15

Slide 15 text

Subscriptions • Common problem: Memory leaks! • Two conditions: • Sequences with references • Delayed (or never) ending Observables

Slide 16

Slide 16 text

Finite, With Reference Observable.just(1).subscribe(this::doSomething);

Slide 17

Slide 17 text

Never-ending, No Reference Observable.never().subscribe();

Slide 18

Slide 18 text

Never-ending, With Reference Observable.interval(1, TimeUnit.SECONDS)
 .subscribe(this::doSomething);

Slide 19

Slide 19 text

Solution • Unsubscribe! Subscription subscription = Observable.just(1).subscribe();
 subscription.unsubscribe(); • General: CompositeSubscription • Android: LifecycleObservable

Slide 20

Slide 20 text

Scheduling Oddities Understanding Schedulers

Slide 21

Slide 21 text

Mysteries Observable.just(1, 2, 3)
 .subscribeOn(Schedulers.newThread())
 .subscribeOn(Schedulers.io())
 .subscribe(System.out::println); • How many threads are spawned? • What thread is just() on? • What thread is subscribe() on?

Slide 22

Slide 22 text

Default Schedulers • Operators can have default schedulers • Example: Observable.interval() • Read the documentation!

Slide 23

Slide 23 text

Hot n Cold …Observables

Slide 24

Slide 24 text

Hot vs. Cold • Hot: Sequences producing notifications regardless of subscriptions • Cold: Sequences that produce notifications on subscription

Slide 25

Slide 25 text

Hot vs. Cold • Hot: Sequences have no subscription side effects. • Cold: Sequences may have subscription side effects.

Slide 26

Slide 26 text

Hot or Not? • Observable.just(“1”) • PublishSubject • ViewObservable.clicks() • Observable.interval() • ReplaySubject

Slide 27

Slide 27 text

Why should I care? • Operations can be expensive • Sometimes you don’t want side effects • Example: Network calls • Sometimes you do want side effects • Example: retry()

Slide 28

Slide 28 text

Temperature Conversion • Hot -> Cold: defer() • Hot -> Cold (incidental): merge(), concat(), etc. • Cold -> Hot: publish()

Slide 29

Slide 29 text

Determining Temperature • You cannot do it • Assume cold

Slide 30

Slide 30 text

Learning to Share …Observables

Slide 31

Slide 31 text

Why Share? • Cold observables generate notifications • Generating notifications can take time

Slide 32

Slide 32 text

Example Observable observable = Observable.create(subscriber -> {
 subscriber.onNext(Calendar.getInstance().getTimeInMillis());
 subscriber.onCompleted();
 });
 
 observable.subscribe(l -> System.out.println("s1: " + l));
 observable.subscribe(l -> System.out.println("s2: " + l)); // Outputs… s1: 1428676059925 s2: 1428676059931

Slide 33

Slide 33 text

Publish • publish() creates a ConnectableObservable • Generates on connect(), not subscribe()

Slide 34

Slide 34 text

publish() Observable observable = Observable.create(subscriber -> {
 subscriber.onNext(Calendar.getInstance().getTimeInMillis());
 subscriber.onCompleted();
 });
 
 ConnectableObservable connectable = observable.publish();
 connectable.subscribe(l -> System.out.println("s1: " + l));
 connectable.subscribe(l -> System.out.println("s2: " + l));
 connectable.connect(); // Outputs… s1: 1428676170160 s2: 1428676170160

Slide 35

Slide 35 text

publish() Observable observable = Observable.create(subscriber -> {
 subscriber.onNext(Calendar.getInstance().getTimeInMillis());
 subscriber.onCompleted();
 });
 
 ConnectableObservable connectable = observable.publish();
 connectable.subscribe(l -> System.out.println("s1: " + l));
 connectable.subscribe(l -> System.out.println("s2: " + l));
 connectable.connect(); // Outputs… s1: 1428676170160 s2: 1428676170160

Slide 36

Slide 36 text

refCount() Observable observable = Observable.create(subscriber -> {
 subscriber.onNext(Calendar.getInstance().getTimeInMillis());
 subscriber.onCompleted();
 }).delay(100, TimeUnit.MILLISECONDS);
 
 Observable connectable = observable.publish().refCount();
 connectable.subscribe(l -> System.out.println("s1: " + l));
 connectable.subscribe(l -> System.out.println("s2: " + l)); // Outputs… s1: 1428676170160 s2: 1428676170160

Slide 37

Slide 37 text

share() Observable observable = Observable.create(subscriber -> {
 subscriber.onNext(Calendar.getInstance().getTimeInMillis());
 subscriber.onCompleted();
 }).delay(100, TimeUnit.MILLISECONDS);
 
 Observable connectable = observable.share();
 connectable.subscribe(l -> System.out.println("s1: " + l));
 connectable.subscribe(l -> System.out.println("s2: " + l)); // Outputs… s1: 1428676170160 s2: 1428676170160

Slide 38

Slide 38 text

Pop Quiz Observable observable = Observable.create(subscriber -> {
 subscriber.onNext(Calendar.getInstance().getTimeInMillis());
 subscriber.onCompleted();
 });
 
 Observable connectable = observable.share();
 connectable.subscribe(l -> System.out.println("s1: " + l));
 connectable.subscribe(l -> System.out.println("s2: " + l)); // Outputs… s1: 1428676059925 s2: 1428676059931

Slide 39

Slide 39 text

Don’t mention the war! Avoiding Subjects

Slide 40

Slide 40 text

Subject • Implements Observer and Observable • Subjects are hot • Easy way to emit items manually to a sequence

Slide 41

Slide 41 text

Track Values • Emit types set in a class public class MyClass {
 
 private String value;
 
 private final BehaviorSubject subject =
 BehaviorSubject.create();
 
 public void setValue(String value) {
 this.value = value;
 subject.onNext(value);
 }
 
 public Observable getValueObservable() {
 return subject.asObservable();
 }
 }

Slide 42

Slide 42 text

Why NOT Subjects? • Mutable state in functional world • Difficult to mix mutation + concurrency • There often exists a simpler solution

Slide 43

Slide 43 text

Avoiding Subjects • If possible, convert data into Observable • Use operators instead • AsyncSubject -> takeLast(1) • PublishSubject -> publish() • ReplaySubject -> replay()/cache() • BehaviorSubject -> replay(1)/cache(1)

Slide 44

Slide 44 text

Under Pressure …Backpressure, that is

Slide 45

Slide 45 text

Backpressure • Producers gonna produce • Consumers gonna consume • Haters gonna hate

Slide 46

Slide 46 text

What if… • Production < consumption? • Production == consumption? • Production > consumption?

Slide 47

Slide 47 text

Produce Less • filter(), distinctUntilChanged() • throttleLast(), throttleFirst(), debounce() • buffer() • onBackPressureDrop()

Slide 48

Slide 48 text

Reactive Pull • Produce on request observable.subscribe(new Subscriber() {
 @Override
 public void onStart() {
 // Start pulling...
 request(1);
 }
 
 @Override
 public void onNext(Integer n) {
 // Use n, then pull again...
 request(1);
 }
 
 // ...Clipped out onError/onCompleted...
 });

Slide 49

Slide 49 text

Operator vs. Pull • Pull - cold Observables • Pull - supported operators • Produce less for everything else

Slide 50

Slide 50 text

More Reading • Composition: http://blog.danlew.net/2015/03/02/dont-break-the- chain/ • Subscriptions: https://github.com/dlew/android-subscription- leaks • Schedulers: http://www.grahamlea.com/2014/07/rxjava- threading-examples/ • Hot vs. Cold: http://davesexton.com/blog/post/Hot-and-Cold- Observables.aspx • Subjects: http://davesexton.com/blog/post/To-Use-Subject-Or- Not-To-Use-Subject.aspx

Slide 51

Slide 51 text

Thanks! • danlew.net • @danlew42