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

RxJava in practice

Jan 09, 2017

Download

Technology

Javier Gamarra
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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