RxJava in practice

Post on 09-Jan-2017

556 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

Transcript

MADRID · NOV 27-28 · 2015

RxJava in practiceJavier Gamarra

MADRID · NOV 27-28 · 2015

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

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

MADRID · NOV 27-28 · 2015

Environment

Eclipse | Android Studio (RxAndroid)

RxJava.jar

[Java 8] || [Retrolambda] :P

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

MADRID · NOV 27-28 · 2015

Github

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

momento

MADRID · NOV 27-28 · 2015

Ask!

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

MADRID · NOV 27-28 · 2015

Background?

MADRID · NOV 27-28 · 2015

Why?

MADRID · NOV 27-28 · 2015

Why? (in java)

multithreading is hard

futures are complicated

callbacks are hell

MADRID · NOV 27-28 · 2015

Rx comes to the rescue!

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

MADRID · NOV 27-28 · 2015

a library

MADRID · NOV 27-28 · 2015

A library?

Extensions to .NET framework

Netflix

MADRID · NOV 27-28 · 2015

Libraries are tools

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

MADRID · NOV 27-28 · 2015

a library to modelObservables & Subscribers

MADRID · NOV 27-28 · 2015

Observables and Subscribers

An Observable emits items.

A Subscriber consumes those items.

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();

}

});

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);

}

};

MADRID · NOV 27-28 · 2015

A bit verbose...

Let’s simplify with Java8 and RxJava

● lamdbas● Observable.just● .subscribe()

MADRID · NOV 27-28 · 2015

That’s better...

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

MADRID · NOV 27-28 · 2015

Why?

More than the observer pattern

● Observables only emit when someone listening

● OnFinished● OnError

MADRID · NOV 27-28 · 2015

Let’s use those differences

subscribe admits 3 parameters

● OnNext● OnFinished● OnError

MADRID · NOV 27-28 · 2015

Ok, let’s recap…

Iterators?

MADRID · NOV 27-28 · 2015

Iterators?

● Iterators are pull and synchronous

● Subscribers are push and asynchronous

MADRID · NOV 27-28 · 2015

to represent any operation as an “asynchronous data stream”

MADRID · NOV 27-28 · 2015

Everything is a stream

MADRID · NOV 27-28 · 2015

Everything is a streamWe can model everything as a

stream

MADRID · NOV 27-28 · 2015

“declaratively composed”

MADRID · NOV 27-28 · 2015

Operators

MADRID · NOV 27-28 · 2015

Operators

Transform a stream

rxmarbles and android app

MADRID · NOV 27-28 · 2015

Operators

Map

MADRID · NOV 27-28 · 2015

Map

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

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

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);

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

MADRID · NOV 27-28 · 2015

Flatmap

Flatmap

Obs -> elements

MADRID · NOV 27-28 · 2015

Flatmap

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

MADRID · NOV 27-28 · 2015

Flatmap

Concatmap -> ordered flatmap

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);

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);

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;

MADRID · NOV 27-28 · 2015

Operators

● merge● flatMap● zip

Nice things™ : parallel jobs!

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());});

MADRID · NOV 27-28 · 2015

Operators

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

MADRID · NOV 27-28 · 2015

Subscribers are asynchronous?

No, not really

MADRID · NOV 27-28 · 2015

“on any thread”

MADRID · NOV 27-28 · 2015

Schedulers!

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 ...

MADRID · NOV 27-28 · 2015

Schedulers

.subscribeOn(Schedulers...)

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

MADRID · NOV 27-28 · 2015

Schedulers

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

MADRID · NOV 27-28 · 2015

Schedulers

RxJava operators have default threads

Interval?

MADRID · NOV 27-28 · 2015

Use cases?

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

MADRID · NOV 27-28 · 2015

Android?

MADRID · NOV 27-28 · 2015

Why?

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

MADRID · NOV 27-28 · 2015

How RxAndroid helps?

MADRID · NOV 27-28 · 2015

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

MADRID · NOV 27-28 · 2015

Orientation Problem

Orientation Problem

● onCreate gets called again● state is lost

MADRID · NOV 27-28 · 2015

Orientation Problem

Programmer’s job:

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

MADRID · NOV 27-28 · 2015

How RxAndroid helps?

MADRID · NOV 27-28 · 2015

Orientation Problem

Observable is easy to persist (retain | singleton)

Observable can continue (cache and retry)

RxLifecycle

MADRID · NOV 27-28 · 2015

Orientation Problem

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

.listRepos("nhpatt")

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.cache();

MADRID · NOV 27-28 · 2015

But...

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

MADRID · NOV 27-28 · 2015

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

subscription.unsubscribe();}

.isUnsubscribed() :(

MADRID · NOV 27-28 · 2015

Let’s recap

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

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable on any thread,

declaratively composed, and consumed by multiple objects

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable with schedulers

declaratively composed, and consumed by multiple objects

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable with schedulersand operators

and consumed by multiple objects

MADRID · NOV 27-28 · 2015

a library to represent any operation as an

observable with schedulersand operators

listened by subscribers

MADRID · NOV 27-28 · 2015

But...

MADRID · NOV 27-28 · 2015

Questions?

MADRID · NOV 27-28 · 2015

Where to know more...

nhpatt (twitter | github | email | slack)

I’ll do anything for good votes

MADRID · NOV 27-28 · 2015

Feedback

Click here :P

MADRID · NOV 27-28 · 2015

RxJava in practiceJavier Gamarra

MADRID · NOV 27-28 · 2015

Other interesting operators...

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);

MADRID · NOV 27-28 · 2015

Errors?

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

MADRID · NOV 27-28 · 2015

Errors

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

MADRID · NOV 27-28 · 2015

Why this is useful?

MADRID · NOV 27-28 · 2015

Why this is useful?

Observables and subscribers can do anything

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable a database query

Subscriber displaying results on the screen

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable a click on the screen

Subscriber reacting to it

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable a stream of bytes from the internet

Subscriber write them to disk

MADRID · NOV 27-28 · 2015

Why this is useful?

Observable and Subscriber are independent of the transformations

MADRID · NOV 27-28 · 2015

Why this is useful?

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

Only matters the return type

MADRID · NOV 27-28 · 2015

Side effects?

MADRID · NOV 27-28 · 2015

Side effects

doOn methods:

● doOnNext() for debugging

● doOnError() for error handling

● doOnNext() to save/cache results

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));

MADRID · NOV 27-28 · 2015

Side effectsflatMap(id -> service.get()

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

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

MADRID · NOV 27-28 · 2015

Cold & Hot

MADRID · NOV 27-28 · 2015

Cold & Hot

Observables only emit when someone listening?

Cold observables only emit when subscribed

But hot observables emit instantly

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()

MADRID · NOV 27-28 · 2015

Cold & Hot

publish & connect?

“like transactions”

Assume everything is cold

MADRID · NOV 27-28 · 2015

Testing?

MADRID · NOV 27-28 · 2015

More cool things?

● testscheduler

● toIterator()

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

MADRID · NOV 27-28 · 2015

Subjects

MADRID · NOV 27-28 · 2015

Subjects

Both observable & observer

MADRID · NOV 27-28 · 2015

Subjects

AsyncSubject -> takeLast(1)

PublishSubject -> publish()

ReplaySubject -> replay()/cache()

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

MADRID · NOV 27-28 · 2015

RxJava in practiceJavier Gamarra

top related