Saving lives with rx java
-
Upload
shahar-barsheshet -
Category
Software
-
view
31 -
download
1
Transcript of Saving lives with rx java
![Page 1: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/1.jpg)
Saving lives with RxJavaShahar Barsheshet
![Page 2: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/2.jpg)
About me
Shahar Barsheshet
shahar2k5
![Page 3: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/3.jpg)
Talk agenda
● Intro to RxJava
● Why and How?
● Common Mistakesand some tips
![Page 4: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/4.jpg)
Do You Rx?
![Page 5: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/5.jpg)
Intro to Rx
Wikipedia:
reactive programming is a programming paradigm oriented around data flows and the
propagation of change. This means that it should be possible to express static or
dynamic data flows with ease in the programming languages used, and that the
underlying execution model will automatically propagate changes through the data flow.
RxJava ← Reactive eXtentions ← Reactive Programing
![Page 6: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/6.jpg)
Mmmm…. Data Flow….
![Page 7: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/7.jpg)
Intro to Rx
Definition from ReactiveX:ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences.
It extends the observer pattern to support sequences of data and/or events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety, concurrent data structures, and non-blocking I/O.
![Page 8: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/8.jpg)
The Problem
Concurrency
![Page 9: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/9.jpg)
The Problem
Some solutions:
● AsyncTask○ Comfortable - nice callbacks○ Error handling sucks - Tuple??○ The lost Context○ Composing multiple calls… oh no!○ Testing… yeah right…
● Threading○ Very hard to handle concurrency○ Bugs are easy to create
● IntentService○ Easy to use○ Updating the UI isn't trivial○ Concurrency…???
![Page 10: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/10.jpg)
The Solution
RxJava● Can easily join background operations● Easy error handling● Can be tied to lifecycle● Easy to test● Remove boilerplate code
![Page 11: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/11.jpg)
RxJava with Android
● RxAndroid - Android Schedulers
● RxBinding - by Jake Wharton
● RxJava
compile 'com.jakewharton.rxbinding:rxbinding:1.0.0'
compile 'io.reactivex:rxandroid:1.2.1'compile 'io.reactivex:rxjava:1.2.6'
compile 'io.reactivex:rxjava:1.2.6'
![Page 12: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/12.jpg)
Rx Concepts
● Observable and the observer contracts
● Operators
● Schedulers
![Page 13: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/13.jpg)
The Observable
Observables emits data when you subscribe to them.
● onNext(0 … ∞)● onComplete(0 … 1)● onError(0 … 1)
onError() and onComplete() are exclusive.
![Page 14: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/14.jpg)
Subscribers and Subscriptions
Once subscribing to an Observable, we get the Subscription object.
The Subscription describes the connection between the Observable and the observer.
As long as we are subscribed, we will get data emitted from the Observable.To stop the Observable from emitting more item, we just need to call
subscription.unsubscribe();
![Page 15: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/15.jpg)
Error handling
When an error occurs, the Observable stop emitting data.onError(Throwable t) gets called so we can handle the error in a proper way.
What happens if we don't implement onError(Throwable t) ?
![Page 16: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/16.jpg)
The Magazine...
Subscribing - creating the Subscription
Preparing dataData ready - user can observe
Error!!!Complete
ObservableObserver
Unsubscribe
![Page 17: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/17.jpg)
Subscribers and Subscriptions
Subscription mySubscription = myIntegers.subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { // YEY!! finished emitting all the integers }
@Override public void onError(Throwable e) { // something bad happened }
@Override public void onNext(Integer integer) { // we just got a new integer }});
Observable<Integer> myIntegers = Observable.just(1, 2, 3, 4, 5);
mySubscription.unsubscribe();
![Page 18: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/18.jpg)
Operators
ReactiveX offers lots of operators to handle and manipulate data.
Creating Observables
● Just — convert an object or a set of objects into an Observable that emits that or those objects● Interval — create an Observable that emits a sequence of integers spaced by a particular time interval● Create — create an Observable from scratch by calling observer methods programmatically
Transforming Observables
● Map — transform the items emitted by an Observable by applying a function to each item
Combining Observables
● Merge — combine multiple Observables into one by merging their emissions● CombineLatest — when an item is emitted by either of two Observables, combine the latest item emitted by each
Observable via a specified function and emit items based on the results of this function
![Page 19: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/19.jpg)
Operators - Map
![Page 20: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/20.jpg)
Operators - Filter
![Page 21: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/21.jpg)
Operators
Observable<Integer> myIntegers = Observable.just(1, 2, 3, 4, 5);
Observable<Integer> evenIntegers = myIntegers.filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer integer) { return integer % 2 == 0; }});
mappedToString.subscribe();
// onNext("Just mapped 2")// onNext("Just mapped 4")// onComplete()
Observable<String> mappedToString = evenIntegers.map(new Func1<Integer, String>() { @Override public String call(Integer integer) { return "Just mapped " + integer; }});
![Page 22: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/22.jpg)
Operators
Observable<Integer> myIntegers = Observable.just(1, 2, 3, 4, 5);
myIntegers.filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer integer) { return integer % 2 == 0; }}).map(new Func1<Integer, String>() { @Override public String call(Integer integer) { return "Just mapped " + integer; }});
![Page 23: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/23.jpg)
Lambda Expression
new Func1<String, Integer>(){ @Override public Integer call(String string) { return string.length(); }};
(String string) ->{ return string.length();};
string -> string.length();= =
![Page 24: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/24.jpg)
Operators
myIntegers .filter(integer -> integer % 2 == 0) .map(integer -> "Just mapped " + integer);
Observable<Integer> myIntegers = Observable.just(1, 2, 3, 4, 5);myIntegers.filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer integer) { return integer % 2 == 0; }}).map(new Func1<Integer, String>() { @Override public String call(Integer integer) { return "Just mapped " + integer; }});
From this:
To this:
![Page 25: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/25.jpg)
Schedulers
By default, an Observable and the chain of operators that you apply to it will do its work, and will notify its observers, on the same thread on which its Subscribe method is called. The SubscribeOn operator changes this behavior by specifying a different Scheduler on which the Observable should operate.
● Schedulers.computation( ) meant for computational work such as event-loops and callback processing
● Schedulers.io( ) meant for I/O-bound work such as asynchronous performance of blocking I/O, this scheduler is backed by a thread-pool that will grow as needed
● AndroidSchedulers.mainThread( ) (using RxAndroid)
subscribeOn() and observeOn
![Page 26: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/26.jpg)
AsyncTask
String userId = "102";
AsyncTask getUserTask = new AsyncTask<String, Void, User>() { @Override protected User doInBackground(String[] strings) { return ServerAPI.getUserProfile(strings[0]); }
@Override protected void onPostExecute(User user) { super.onPostExecute(user); mAdapter.add(user.firstName + " " + user.lastName); }};
getUserTask.execute(userId);
![Page 27: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/27.jpg)
AsyncTask
String userId = "102";
Observable.just(userId) .map(id -> ServerAPI.getUserProfile(id)) .subscribe(user -> { mAdapter.add(user.firstName + " " + user.lastName); }, throwable -> { Toast.makeText(this, "An error occurred, please try again" , Toast.LENGTH_SHORT).show(); });
Observable.just(userId) .map(id -> ServerAPI.getUserProfile(id)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(user -> { mAdapter.add(user.firstName + " " + user.lastName); }, throwable -> { Toast.makeText(this, "An error occurred, please try again" , Toast.LENGTH_SHORT).show(); });
![Page 28: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/28.jpg)
TimerTask
//initialize the TimerTask's jobTimerTask timerTask = new TimerTask() { @Override public void run() { // Do some cool stuff // on the UI Thread }};
//set a new TimerTimer timer = new Timer();
//schedule the timer, after the first 5000ms// the TimerTask will run every 10000mstimer.schedule(timerTask, 5000, 10000);
![Page 29: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/29.jpg)
TimerTask
Observable.interval(5000, 10000, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe(interval -> { // Do some cool stuff
// on the UI Thread });
public static Observable<Long> interval(long initialDelay, long period, TimeUnit unit) { return interval(initialDelay, period, unit, Schedulers.computation());}
![Page 30: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/30.jpg)
Search address using Google Places API
mEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { GetPlaces task = new GetPlaces(); String check = mEditText.getText().toString(); task.execute(check); }
@Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override public void afterTextChanged(Editable editable) {}});
// get the list of predictions in an asynctaskclass GetPlaces extends AsyncTask<String, Void, ArrayList<String>> {
@Override protected ArrayList<String> doInBackground(String... args) { ArrayList<String> predictionsArr = new ArrayList<String>(); try { ServerAPI.getSuggestionsFromGoogleAPI(args[0]); } catch (Exception e) { e.printStackTrace(); } // return all the predictions based on the typing the in the search return predictionsArr; }
@Override protected void onPostExecute(ArrayList<String> result) { // update the list with new data }}
![Page 31: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/31.jpg)
Search address using Google Places API - using RxJava
RxTextView.textChanges(mEditText) .debounce(300, TimeUnit.MILLISECONDS) .distinctUntilChanged() .filter(charSequence -> charSequence != null && charSequence.length() > 0) .map(charSequence -> ServerAPI.getSuggestionsFromGoogleAPI(charSequence)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnError(throwable -> { // show user something about this error }) .subscribe(strings -> { // update the list with new data });
![Page 32: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/32.jpg)
Getting the current country
NetworkProvider
IP
GPS
![Page 33: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/33.jpg)
Getting the current country
public Observable<CountryProvider> getCountryCode(){ Observable<CountryProvider> locationObservable = getCountryFromLocationProvider(); Observable<CountryProvider> ipObservable = getCountryFromNetwork(); Observable<CountryProvider> providerObservable = getCountryFromNetworkProvider();
return Observable.merge(providerObservable, locationObservable, ipObservable) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .startWith(new CountryProvider("il", CountryProviderType.DEFAULT)) .scan((countryProvider, countryProvider2) -> { if (countryProvider2 == null) { return countryProvider; } int value1 = countryProvider.getProviderType().getValue(); int value2 = countryProvider2.getProviderType().getValue(); return value1 > value2 ? countryProvider : countryProvider2; }) .distinctUntilChanged() .onErrorReturn(null);}
![Page 34: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/34.jpg)
Getting the current country
mCountryManager.getCountryCode() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(countryProvider -> { Toast.makeText(this, "Got country " + countryProvider.getCountryCode() + " from provider: " + countryProvider.getProviderType().name() , Toast.LENGTH_LONG).show(); });
![Page 35: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/35.jpg)
CommonMistakesAnd Tips
![Page 36: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/36.jpg)
Default Schedulers
Observable.just("hello") .subscribe(); → happens on the current thread
Observable.just("hello") .delay(1000, TimeUnit.MILLISECONDS) .subscribe(); → happens on the computation thread
VS
![Page 37: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/37.jpg)
Multiple SubscribeOn
Observable.just("Hello") .subscribeOn(Schedulers.io()) .map(string -> string.length()) .subscribeOn(Schedulers.computation()) .subscribe();
io()
![Page 38: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/38.jpg)
ObserveOn
Observable.just("Hello") // current thread .observeOn(Schedulers.io()) .map(string -> string.length()) // io .observeOn(Schedulers.computation()) .subscribe(); // computation
Multiple observeOn do work as expected.
![Page 39: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/39.jpg)
Memory leak
● Subscribers can leak!
● Use leakcanary
● Unsubscribe when leaving
![Page 40: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/40.jpg)
Unsubscribe
Subscription subscription = Observable.just("Hello").subscribe();subscription.unsubscribe();
![Page 41: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/41.jpg)
CompositeSubscription
Subscription myIntegerSubscription = myIntegers.subscribe(new Subscriber<Integer>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(Integer integer) {}});Subscription myStringSubscription = myStrings.subscribe(new Subscriber<String>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String string) {}});compositeSubscription.add(myIntegerSubscription);compositeSubscription.add(myStringSubscription);
Observable<Integer> myIntegers = Observable.just(1, 2, 3, 4, 5);Observable<String> myStrings = Observable.just("one", "two", "three", "four", "five");
compositeSubscription.unsubscribe();// ORcompositeSubscription.clear();
CompositeSubscription compositeSubscription = new CompositeSubscription();
![Page 42: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/42.jpg)
LifeCycle
private CompositeSubscription mSubscriptions;
@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mSubscriptions = new CompositeSubscription();}
@Overridepublic void onDestroyView() { super.onDestroyView(); if (!mSubscriptions.isUnsubscribed()) mSubscriptions.unsubscribe();}
public void addSubscriptionToViewLifeCycle(Subscription subscription) { mSubscriptions.add(subscription);}
![Page 43: Saving lives with rx java](https://reader034.fdocuments.us/reader034/viewer/2022042707/58cf32821a28ab00168b5c09/html5/thumbnails/43.jpg)
Thanks!By the way
We are hiring!Shahar Barsheshet
Source code