RxJava in practice

111
MADRID · NOV 27-28 · 2015 RxJava in practice Javier Gamarra

Transcript of RxJava in practice

Page 1: RxJava in practice

MADRID · NOV 27-28 · 2015

RxJava in practiceJavier Gamarra

Page 2: RxJava in practice

MADRID · NOV 27-28 · 2015

http://kcy.me/29crj (slides)&

http://kcy.me/296bu (commits)

Page 3: RxJava in practice

MADRID · NOV 27-28 · 2015

Environment

Eclipse | Android Studio (RxAndroid)

RxJava.jar

[Java 8] || [Retrolambda] :P

Page 4: RxJava in practice

MADRID · NOV 27-28 · 2015

Environment

Android Studio:compile 'io.reactivex:rxandroid:1.0.1'compile 'io.reactivex:rxjava:1.0.16'

Eclipse:● Copy jars to lib/ and add jar in project

Page 5: RxJava in practice

MADRID · NOV 27-28 · 2015

Github

● http://kcy.me/296bu● koans● código● commit a commit● Podéis preguntarme en cualquier

momento

Page 7: RxJava in practice

MADRID · NOV 27-28 · 2015

Ask!

Please? Pretty please? Please pretty please with sugar on top?

Page 8: RxJava in practice

MADRID · NOV 27-28 · 2015

Background?

Page 9: RxJava in practice

MADRID · NOV 27-28 · 2015

Why?

Page 10: RxJava in practice

MADRID · NOV 27-28 · 2015

Why? (in java)

multithreading is hard

futures are complicated

callbacks are hell

Page 11: RxJava in practice

MADRID · NOV 27-28 · 2015

Rx comes to the rescue!

Page 12: RxJava in practice

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

asynchronous data stream on any thread,

declaratively composed, and consumed by multiple objects

Page 13: RxJava in practice

MADRID · NOV 27-28 · 2015

a library

Page 14: RxJava in practice

MADRID · NOV 27-28 · 2015

A library?

Extensions to .NET framework

Netflix

Page 15: RxJava in practice

MADRID · NOV 27-28 · 2015

Libraries are tools

If all you have is a hammer, everything looks like a nail

Page 16: RxJava in practice

MADRID · NOV 27-28 · 2015

a library to modelObservables & Subscribers

Page 17: RxJava in practice

MADRID · NOV 27-28 · 2015

Observables and Subscribers

An Observable emits items.

A Subscriber consumes those items.

Page 19: RxJava in practice

MADRID · NOV 27-28 · 2015

My very first observableObservable<String> myObs = Observable. create(new Observable.

OnSubscribe<String>() {

@Override

public void call(Subscriber<? super String> subscriber) {

subscriber.onNext( "Hi!");

subscriber.onCompleted();

}

});

Page 20: RxJava in practice

MADRID · NOV 27-28 · 2015

My very first subscriberSubscriber<String> mySubs = new Subscriber<String>() {

@Override

public void onCompleted() {

}

@Override

public void onError(Throwable throwable) {

}

@Override

public void onNext(String s) {

System.out.println(s);

}

};

Page 22: RxJava in practice

MADRID · NOV 27-28 · 2015

A bit verbose...

Let’s simplify with Java8 and RxJava

● lamdbas● Observable.just● .subscribe()

Page 23: RxJava in practice

MADRID · NOV 27-28 · 2015

That’s better...

Observable.just("Hi!").subscribe(System.out::println);

Page 24: RxJava in practice

MADRID · NOV 27-28 · 2015

Why?

More than the observer pattern

● Observables only emit when someone listening

● OnFinished● OnError

Page 25: RxJava in practice

MADRID · NOV 27-28 · 2015

Let’s use those differences

subscribe admits 3 parameters

● OnNext● OnFinished● OnError

Page 27: RxJava in practice

MADRID · NOV 27-28 · 2015

Ok, let’s recap…

Iterators?

Page 28: RxJava in practice

MADRID · NOV 27-28 · 2015

Iterators?

● Iterators are pull and synchronous

● Subscribers are push and asynchronous

Page 29: RxJava in practice

MADRID · NOV 27-28 · 2015

to represent any operation as an “asynchronous data stream”

Page 30: RxJava in practice

MADRID · NOV 27-28 · 2015

Everything is a stream

Page 31: RxJava in practice

MADRID · NOV 27-28 · 2015

Everything is a streamWe can model everything as a

stream

Page 33: RxJava in practice

MADRID · NOV 27-28 · 2015

“declaratively composed”

Page 34: RxJava in practice

MADRID · NOV 27-28 · 2015

Operators

Page 35: RxJava in practice

MADRID · NOV 27-28 · 2015

Operators

Transform a stream

rxmarbles and android app

Page 36: RxJava in practice

MADRID · NOV 27-28 · 2015

Operators

Map

Page 37: RxJava in practice

MADRID · NOV 27-28 · 2015

Map

List<String> severalThings = Arrays.asList("1", "2");

Observable.from(severalThings) .map((s) -> “Element “ + s) .subscribe(System.out::println);

Page 38: RxJava in practice

MADRID · NOV 27-28 · 2015

Map

We can return another type:List<String> severalThings = Arrays.asList("1", "2");

Observable.from(severalThings) .map(Integer::valueOf) .subscribe(System.out::println);

Page 39: RxJava in practice

MADRID · NOV 27-28 · 2015

Map

Let’s do the same with our repos…

And… I can’t because we return a List

And using Observable.from… NOP

Page 40: RxJava in practice

MADRID · NOV 27-28 · 2015

Flatmap

Flatmap

Obs -> elements

Page 41: RxJava in practice

MADRID · NOV 27-28 · 2015

Flatmap

service.listRepos("nhpatt") .flatMap(Observable::from) .map(Repo::getName) .map((s) -> s.replace("-", " ")) .subscribe(System.out::println);

Page 42: RxJava in practice

MADRID · NOV 27-28 · 2015

Flatmap

Concatmap -> ordered flatmap

Page 43: RxJava in practice

MADRID · NOV 27-28 · 2015

Filter

service.listRepos("nhpatt") .flatMap(Observable::from) .map(Repo::getName) .map((s) -> s.replace("-", " ")) .filter((s) -> s.startsWith("Android")) .subscribe(System.out::println);

Page 44: RxJava in practice

MADRID · NOV 27-28 · 2015

Scan & old codeservice.listRepos("nhpatt") .flatMap(Observable::from) .map(Repo::getName) .map((s) -> s.replace("-", " ")) .filter((s) -> s.startsWith("Android")) .take(2) .map(String::length) .scan((x, y) -> x * y) .subscribe(System.out::println);

Page 45: RxJava in practice

MADRID · NOV 27-28 · 2015

Scan & old code(l) -> {

int result = 0;int i = 0;int oldLength = 1;

for (Repo repo : l) {String name = repo.getName();String replacedName = name.replace( "-", " ");

if (replacedName.startsWith( "Android") && i < 2) {result = replacedName.length() * oldLength;oldLength = result;System.out.println(result);i++;

}

}return result;

Page 46: RxJava in practice

MADRID · NOV 27-28 · 2015

Operators

● merge● flatMap● zip

Nice things™ : parallel jobs!

Page 47: RxJava in practice

MADRID · NOV 27-28 · 2015

Zipping requestsObservable<Repo> repo = service.listRepos("nhpatt") .flatMap(Observable::from) .take(1);

Observable<Commit> commit = service.listCommits("nhpatt", "Android") .flatMap(Observable::from) .take(1);

Observable.zip(repo, commit, this::updateCommit).subscribe(repo1 -> { System.out.println(repo1.getCommit().getUrl());});

Page 48: RxJava in practice

MADRID · NOV 27-28 · 2015

Operators

Amazing documentation● Async● Blocking● Combining● Conditional● Error handling● Filtering● Mathematical● Creation● String● Transforming● Utility

Page 49: RxJava in practice

MADRID · NOV 27-28 · 2015

Subscribers are asynchronous?

No, not really

Page 50: RxJava in practice

MADRID · NOV 27-28 · 2015

“on any thread”

Page 51: RxJava in practice

MADRID · NOV 27-28 · 2015

Schedulers!

Page 52: RxJava in practice

MADRID · NOV 27-28 · 2015

Schedulers

I define an API declaratively and later in the implementation run it:

asynchronously or in a separate Thread or in a Threadpool or synchronously ...

Page 53: RxJava in practice

MADRID · NOV 27-28 · 2015

Schedulers

.subscribeOn(Schedulers...)

.observeOn(Schedulers...)● io● computation● newThread● trampoline● test

Page 54: RxJava in practice

MADRID · NOV 27-28 · 2015

Schedulers

service.listRepos("nhpatt") .subscribeOn(Schedulers.immediate()) .observeOn(Schedulers.immediate()) .subscribe(System.out::println);

Page 55: RxJava in practice

MADRID · NOV 27-28 · 2015

Schedulers

RxJava operators have default threads

Interval?

Page 56: RxJava in practice

MADRID · NOV 27-28 · 2015

Use cases?

Page 57: RxJava in practice

MADRID · NOV 27-28 · 2015

Use cases

● Autocomplete with debounce | sample…● Accumulate calls with buffer...● Polling with timeout | window…● Form Validation with combineLatest…● Retrieve data fast from cache | network call with

concat | merge…● Button click with delay, listen on other thread

Page 58: RxJava in practice

MADRID · NOV 27-28 · 2015

Android?

Page 59: RxJava in practice

MADRID · NOV 27-28 · 2015

Why?

Page 60: RxJava in practice

MADRID · NOV 27-28 · 2015

Why? (in android)

Main/UI thread and background problem

● Can’t do heavy tasks on UI● Can’t update view on background● AsyncTasks are bad● Handlers can leak

Page 61: RxJava in practice

MADRID · NOV 27-28 · 2015

How RxAndroid helps?

Page 62: RxJava in practice

MADRID · NOV 27-28 · 2015

Android schedulersservice.listRepos("nhpatt") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(newRepos -> { repos.addAll(newRepos); adapter.notifyDataSetChanged(); });

Page 63: RxJava in practice

MADRID · NOV 27-28 · 2015

Orientation Problem

Orientation Problem

● onCreate gets called again● state is lost

Page 64: RxJava in practice

MADRID · NOV 27-28 · 2015

Orientation Problem

Programmer’s job:

● Store/Restore state● Restore view● Call again the user task? ● Wait until it finishes?

Page 65: RxJava in practice

MADRID · NOV 27-28 · 2015

How RxAndroid helps?

Page 66: RxJava in practice

MADRID · NOV 27-28 · 2015

Orientation Problem

Observable is easy to persist (retain | singleton)

Observable can continue (cache and retry)

RxLifecycle

Page 67: RxJava in practice

MADRID · NOV 27-28 · 2015

Orientation Problem

Observable<List<Repo>> github = RetrofitService.getGithub()

.listRepos("nhpatt")

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.cache();

Page 69: RxJava in practice

MADRID · NOV 27-28 · 2015

But...

Page 70: RxJava in practice

MADRID · NOV 27-28 · 2015

But...

Subscriptions leak memory :’(

We have to call to unsubscribe (CompositeSubscription helps)

And don’t include references to the object/activity

Page 71: RxJava in practice

MADRID · NOV 27-28 · 2015

Easy to unsubscribe@Overrideprotected void onStop() { super.onStop();

subscription.unsubscribe();}

.isUnsubscribed() :(

Page 72: RxJava in practice

MADRID · NOV 27-28 · 2015

Let’s recap

Page 73: RxJava in practice

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

asynchronous data stream on any thread,

declaratively composed, and consumed by multiple objects

Page 74: RxJava in practice

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable on any thread,

declaratively composed, and consumed by multiple objects

Page 75: RxJava in practice

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable with schedulers

declaratively composed, and consumed by multiple objects

Page 76: RxJava in practice

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable with schedulersand operators

and consumed by multiple objects

Page 77: RxJava in practice

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable with schedulersand operators

listened by subscribers

Page 78: RxJava in practice

MADRID · NOV 27-28 · 2015

But...

Page 79: RxJava in practice

MADRID · NOV 27-28 · 2015

But...

● Learning curve

● Hard to debug (Frodo library)

● Backpressure

Page 80: RxJava in practice

MADRID · NOV 27-28 · 2015

Questions?

Page 82: RxJava in practice

MADRID · NOV 27-28 · 2015

Where to know more...

nhpatt (twitter | github | email | slack)

I’ll do anything for good votes

Page 83: RxJava in practice

MADRID · NOV 27-28 · 2015

Feedback

Click here :P

Page 84: RxJava in practice

MADRID · NOV 27-28 · 2015

RxJava in practiceJavier Gamarra

Page 85: RxJava in practice

MADRID · NOV 27-28 · 2015

Other interesting operators...

Page 86: RxJava in practice

MADRID · NOV 27-28 · 2015

Takeservice.listRepos("nhpatt") .flatMap(Observable::from) .map(Repo::getName) .map((s) -> s.replace("-", " ")) .filter((s) -> s.startsWith("Android")) .take(2) .subscribe(System.out::println);

Page 87: RxJava in practice

MADRID · NOV 27-28 · 2015

Operators

distinctUntilChanged

compose

Page 88: RxJava in practice

MADRID · NOV 27-28 · 2015

Errors?

Page 89: RxJava in practice

MADRID · NOV 27-28 · 2015

onError() is called if an Exception is thrown at any time (this is cool)

The operators don't have to handle the Exception

No more callbacks

Errors

Page 90: RxJava in practice

MADRID · NOV 27-28 · 2015

Errors

And we can customize the flow: onErrorResumeNext onErrorReturn retry ...

Page 91: RxJava in practice

MADRID · NOV 27-28 · 2015

Why this is useful?

Page 92: RxJava in practice

MADRID · NOV 27-28 · 2015

Why this is useful?

Observables and subscribers can do anything

Page 93: RxJava in practice

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable a database query

Subscriber displaying results on the screen

Page 94: RxJava in practice

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable a click on the screen

Subscriber reacting to it

Page 95: RxJava in practice

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable a stream of bytes from the internet

Subscriber write them to disk

Page 96: RxJava in practice

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable and Subscriber are independent of the transformations

Page 97: RxJava in practice

MADRID · NOV 27-28 · 2015

Why this is useful?

I can compose/chain any map/filter calls I want

Only matters the return type

Page 98: RxJava in practice

MADRID · NOV 27-28 · 2015

Side effects?

Page 99: RxJava in practice

MADRID · NOV 27-28 · 2015

Side effects

doOn methods:

● doOnNext() for debugging

● doOnError() for error handling

● doOnNext() to save/cache results

Page 100: RxJava in practice

MADRID · NOV 27-28 · 2015

Side effectsObservable someObservable = Observable .from(Arrays.asList(new Integer[]{2, 7, 11})) .doOnNext(System.out::println) .filter(prime -> prime % 2 == 0) .doOnNext(System.out::println) .count() .doOnNext(System.out::println) .map(

number -> String.format(“Contains %d elements”, number));

Page 101: RxJava in practice

MADRID · NOV 27-28 · 2015

Side effectsflatMap(id -> service.get()

.doOnError(t -> {// report problem to UI

}).onErrorResumeNext(Observable.empty()))

Page 102: RxJava in practice

MADRID · NOV 27-28 · 2015

Cold & Hot

Page 103: RxJava in practice

MADRID · NOV 27-28 · 2015

Cold & Hot

Observables only emit when someone listening?

Cold observables only emit when subscribed

But hot observables emit instantly

Page 104: RxJava in practice

MADRID · NOV 27-28 · 2015

Cold & Hot

You can convert between both states

● “Hot -> cold” using defer() or merge(), zip()...

● “Cold -> Hot” using publish() & connect()

Page 105: RxJava in practice

MADRID · NOV 27-28 · 2015

Cold & Hot

publish & connect?

“like transactions”

Assume everything is cold

Page 106: RxJava in practice

MADRID · NOV 27-28 · 2015

Testing?

Page 107: RxJava in practice

MADRID · NOV 27-28 · 2015

More cool things?

● testscheduler

● toIterator()

● Obs.error(), Obs.empty()

Page 108: RxJava in practice

MADRID · NOV 27-28 · 2015

Subjects

Page 109: RxJava in practice

MADRID · NOV 27-28 · 2015

Subjects

Both observable & observer

Page 110: RxJava in practice

MADRID · NOV 27-28 · 2015

Subjects

AsyncSubject -> takeLast(1)

PublishSubject -> publish()

ReplaySubject -> replay()/cache()

BehaviorSubject -> replay(1)/cache(1)

Page 111: RxJava in practice

MADRID · NOV 27-28 · 2015

RxJava in practiceJavier Gamarra