Recipes in RxJava for Android

Slides:



Advertisements
Similar presentations
Concurrency (p2) synchronized (this) { doLecture(part2); } synchronized (this) { doLecture(part2); }
Advertisements

Cosc 5/4730 Android: “Dynamic” data.. Saving Dynamic data. While there are a lot of ways to save data – Via the filesystem, database, etc. You can also.
Cosc 5/4730 Android Services. What is a service? From android developer web pages: Most confusion about the Service class actually revolves around what.
Programming with Android: Activities
All About Android Introduction to Android 1. Creating a New App “These aren’t the droids we’re looking for.” Obi-wan Kenobi 1. Bring up Eclipse. 2. Click.
Designing a thread-safe class  Store all states in public static fields  Verifying thread safety is hard  Modifications to the program hard  Design.
Contiki A Lightweight and Flexible Operating System for Tiny Networked Sensors Presented by: Jeremy Schiff.
Concurrent Processes Lecture 5. Introduction Modern operating systems can handle more than one process at a time System scheduler manages processes and.
Threads II. Review A thread is a single flow of control through a program Java is multithreaded—several threads may be executing “simultaneously” If you.
Data Storage: Part 1 (Preferences)
Android Mobile computing for the rest of us.* *Prepare to be sued by Apple.
Reactive Extensions Ye olde introduction and walk-through, with plenty o’ code.
Threading and Concurrency Issues ● Creating Threads ● In Java ● Subclassing Thread ● Implementing Runnable ● Synchronization ● Immutable ● Synchronized.
1 Kyung Hee University Diagram Editor : Implementation View Spring 2001.
1 (Worker Queues) cs What is a Thread Pool? A collection of threads that are created once (e.g. when a server starts) That is, no need to create.
CS 346 – Chapter 4 Threads –How they differ from processes –Definition, purpose Threads of the same process share: code, data, open files –Types –Support.
ANDROID L. Grewe Components  Java Standard Development Kit (JDK) (download) (latest version)  AndroidStudio.
Services A Service is an application component that can perform long-running operations in the background and does not provide a user interface. An application.
1 Threads Chapter 11 from the book: Inter-process Communications in Linux: The Nooks & Crannies by John Shapley Gray Publisher: Prentice Hall Pub Date:
Copyright © 2007 InSTech Joint Laboratory All rights reserved. 1 Consideration on Persistence of WiseMan FuDan-Hitachi InSTech (Innovative Software Technology)
Multithreaded programming  Java provides built-in support for multithreaded programming. A multithreaded program contains two or more parts that can run.
Android: “Dynamic” data and Preferences data.
Android Application Lifecycle and Menus
Services Background operating component without a visual interface Running in the background indefinitely Differently from Activity, Service in Android.
Lecture 6: Process and Threads Topics: Process, Threads, Worker Thread, Async Task Date: Mar 1, 2016.
Speech Service & client(Activity) 오지영.
Concurrent Programming in Java Based on Notes by J. Johns (based on Java in a Nutshell, Learning Java) Also Java Tutorial, Concurrent Programming in Java.
1 Stacks Abstract Data Types (ADTs) Stacks Application to the analysis of a time series Java implementation of a stack Interfaces and exceptions.
2.2 Threads  Process: address space + code execution  There is no law that states that a process cannot have more than one “line” of execution.  Threads:
Services. What is a Service? A Service is not a separate process. A Service is not a thread. A Service itself is actually very simple, providing two main.
1 © 2017 Pearson Education, Inc. Hoboken, NJ. All rights reserved. for-each PROS easy to use access to ALL items one-by-one ability to change the state.
Concurrency in Android
for-each PROS CONS easy to use access to ALL items one-by-one
Chapter 4: Threads.
Processes and threads.
Mobile Application Development BSCS-7 Lecture # 6
Decisions Chapter 4.
Advanced Topics in Concurrency and Reactive Programming: The Observable Contract Majeed Kassis.
CS240: Advanced Programming Concepts
Heterogeneous Programming
Activities and Intents
Android Activities An application can have one or more activities, where Each activity Represents a screen that an app present to its user Extends the.
Chapter 5 Conclusion CIS 61.
android architecture components with mvvm
Reactive Android Development
Array.
Chapter 4: Threads.
Android Application Development android.cs.uchicago.edu
Developing Android Services
Advanced Topics in Concurrency and Reactive Programming: ReactiveX
Android Programming Lecture 8
Threads and Multithreading
Multithreaded Programming
Threads and Concurrency
Android Topics Asynchronous Callsbacks
Activities and Intents
Stacks Abstract Data Types (ADTs) Stacks
Threads in Java James Brucker.
Service Services.
CSE 153 Design of Operating Systems Winter 19
SE4S701 Mobile Application Development
Outline Chapter 3: Processes Chapter 4: Threads So far - Next -
Rx Java intro Vaidas Kriščeliūnas.
Activities and Fragments
Android Development Tools
Software Engineering and Architecture
Dynamic Binary Translators and Instrumenters
Threads CSE 2431: Introduction to Operating Systems
Chapter 4:Threads Book: Operating System Principles , 9th Edition , Abraham Silberschatz, Peter Baer Galvin, Greg Gagne.
Presentation transcript:

Recipes in RxJava for Android Sasa Sekulic co-author of the Manning book “Grokking Rx”(with Fabrizio Chignoli and Ivan Morgillo); developer of the UN-WFP ShareTheMeal app; cofounder of Alter Ego Solutions @sasa_sekulic | www.alterego.solutions | Grokking Rx MEAP: http://bit.ly/grokking-rx

UN World Food Programme - ShareTheMeal We provide food to schoolchildren in need – over 5.000.000 meals shared! It costs only €0.40 to feed one child for a day. www.sharethemeal.org Google Play Best of 2015 & Editor's Choice, SXSW 2015 Innovation Award Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic Basics of RxJava Observer Observable Subscription Subscriber (Observer & Subscription) Subject (Observer & Observable) Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Observable creation from any object just(), from() – simple, executed immediately upon creation create() – executed upon subscription but need to take care of contract calls defer()/fromCallable() – simple, but executed upon subscription Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Observable creation –example 1: too simple just(), from() – simple, executed immediately upon creation public Observable<Boolean> exampleBlocking() { SharedPreferences prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE); return Observable.just(prefs.getBoolean("boolean", false)); } Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Observable creation –example 2: too complicated create() – executed upon subscription but need to take care of contract calls public Observable<Boolean> exampleTooComplicated() { SharedPreferences prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE); return Observable.create(new Observable.OnSubscribe<Boolean>() { @Override public void call(Subscriber<? super Boolean> subscriber) { if (subscriber.isUnsubscribed()) { return; } subscriber.onNext(prefs.getBoolean("boolean", false)); if (!subscriber.isUnsubscribed()) { subscriber.onCompleted(); }); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Observable creation –create() isn't as easy as it looks think about the unsubscription/backpressure chain Observable.create(s -> { int i = 0; while (true) { s.onNext(i++); } }).subscribe(System.out::println); for list of many more other problems: http://akarnokd.blogspot.hu/2015/05/pitfalls-of-operator-implementations.html Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Observable creation –example 3: just right defer() – simple, but executed upon subscription fromCallable() – the same, for methods that return values public Observable<Boolean> exampleJustRight() { SharedPreferences prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE); return Observable.defer(new Func0<Observable<Boolean>>() { @Override public Observable<Boolean> call() { return Observable.just(prefs.getBoolean("boolean", false)); } }); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Observable creation –special case of from() from(Future<? extends T>) – blocking, cannot unsubscribe (but you can specify timeout or Scheduler) from(Iterable<? extends T>), from(T[]) – convert Iterable/array event into events from Iterable/array List<Boolean> list = new ArrayList<>(); Observable.just(list).subscribe(new Observer<List<Boolean>>(){ ... } //takes List<Boolean>, emits List<Boolean> Observable.from(list).subscribe(new Observer<Boolean>(){ ... } //takes List<Boolean>, emits Boolean items from the list Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Observable creation –forEach() equivalent ops List<Boolean> list = new ArrayList<>(); Observable.from(list) .map(aBoolean -> !aBoolean) //returns value .flatMap(aBoolean -> Observable.just(aBoolean.hashCode()) //returns observable<value> .toList() //or .toSortedList() .subscribe(new Observer<List<Integer>>() { ... Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic Subjects they're Hot observables – the values are generated independently of existence of subscribers use them to send values to Observers outside creation block enable you to have communication between the Observer and Observable-value generator access onNext(), onError() and onCompleted() whenever you want single-threaded by default, don't mix threads when calling onXXX()! for thread safety, wrap them in a SerializedSubject() or call Subject.toSerialized().onXXX() Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic Subjects - types PublishSubject – doesn’t store any states, just sends what it receives while subscribed (you miss anything in between) – epitome of Hot observable BehaviourSubject – remembers the last value – emptied after onCompleted()/onError() - can be initialized with a value Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic Subjects – types, cont'd AsyncSubject – remembers the last value – after onCompleted() subscribers receive the last value and the onCompleted() event – after onError() subscribers receive just the onError() event ReplaySubject – remembers everything but can be limited (create(int bufferCapacity), createWithSize(int size), createWithTime(long time, TimeUnit unit, final Scheduler scheduler), createWithTimeAndSize(long time, TimeUnit unit, int size, final Scheduler scheduler)) Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subjects – music player example UX Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subjects – music player example states Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subjects – music player example Observer public class MusicPlayer { public enum PLAYER_STATE {STOPPED, PLAYING} Observer<PLAYER_STATE> playerObserver = new Observer<PLAYER_STATE>() { @Override public void onNext(PLAYER_STATE state) { currentPlayerState = state; if (state == PLAYER_STATE.PLAYING) { startSong(); showPauseButton(); } else if (state == PLAYER_STATE.STOPPED) { stopSong(); showPlayButton(); } ... }; Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subjects – music player example Subject public class MusicPlayer { PLAYER_STATE currentPlayerState = PLAYER_STATE.STOPPED; BehaviorSubject<PLAYER_STATE> playerStateSubject = BehaviorSubject.create(currentPlayerState); public MusicPlayer() { playerStateSubject.subscribe(playerObserver); } private void pressButton() { if (currentPlayerState == PLAYER_STATE.PLAYING) { playerStateSubject.onNext(PLAYER_STATE.STOPPED); } else if (currentPlayerState == PLAYER_STATE.STOPPED) { playerStateSubject.onNext(PLAYER_STATE.PLAYING); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subjects – music player example optimization We don't need currentPlayerState, just use playerStateSubject.getValue() Don't expose Subject to others: when offering them for subscribing, use getObservable() public Observable<PLAYER_STATE> getPlayerStateObservable() { return playerStateSubject.asObservable(); } Use Subscription to control Observer lifecycle! Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic Subscription Subscription is a relationship between the Observer and the Observable public MusicPlayer() { Subscription stateSub = playerStateSubject.subscribe(playerObserver); } Subscription is returned by the subscribe() Subscription stateSub = playerStateSubject //Observable .filter(state -> state == PLAYING) //Observable .map(state -> someMethod()) //Observable .subscribe(playerObserver); //Subscription Very simple: isUnsubscribed(), unsubscribe() Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic Subscription – usage To control the lifecycle and/or release the resources, call it in onPause()/onStop()/onDestroy(): @Override protected void onDestroy() { super.onDestroy(); if (mPlayerSubscription != null && !mPlayerSubscription.isUnsubscribed()) { mPlayerSubscription.unsubscribe(); } If you don't want to do null checks, initialize the subscription: Subscription mPlayerSubscription = Subscriptions.unsubscribed(); //or Subscriptions.empty(); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subscription – usage, cont'd To prevent multiple executions/subscriptions: public MusicPlayer() { if (mPlayerSubscription == null || mPlayerSubscription.isUnsubscribed()) { mPlayerSubscription = playerStateSubject.subscribe(playerObserver); } Important: unsubscribing has no impact on the observable or other subscriptions! Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

CompositeSubscription – grouping Subscriptions When you need to control multiple subscriptions at the same time: CompositeSubscription activitySubscriptions = new CompositeSubscription(); @Override protected void onCreate() { mPlayerSub = playerStateSubject.subscribe(playerObserver); mPlayerSub2 = playerStateSubject.subscribe(playerObserver2); activitySubscriptions = new CompositeSubscriptions(mPlayerSub, mPlayerSub2); } protected void onResume() { mPlayerSub3 = playerStateSubject.subscribe(playerObserver3); activitySubscriptions.add(mPlayerSub3); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

CompositeSubscription – grouping Subscriptions (cont'd) When you need to control multiple subscriptions at the same time: removing with remove(), unsubscribing all with unsubscribe(), and clear() unsubscribes all and removes them from the CompositeSubscription: @Override protected void onPause() { mPlayerSub3 = playerStateSubject.subscribe(playerObserver3); activitySubscriptions.remove(mPlayerSub3); } protected void onDestroy() { super.onDestroy(); if (activitySubscriptions.hasSubscriptions() && !activitySubscriptions.isUnsubscribed()) { activitySubscriptions.unsubscribe(); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subscription –control the lifecycle Manually, on the Activity or Fragment level – create when you want, unsubscribe in onPause()/onStop()/onDestroy() Automatically, on the Activity or Fragment level – use https://github.com/trello/RxLifecycle public class MainActivity extends RxAppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { Observable.interval(1, TimeUnit.SECONDS) .compose(this.<Long>bindUntilEvent(ActivityEvent.PAUSE)) //binds to onPause() .subscribe(onCreateObserver); } .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY)) //binds to onDestroy() .compose(this.<Long>bindToLifecycle()) //binds automatically to opposite method (if called from onResume() it will be bound to onPause() One very important note: RxLifecycle doesn't call unsubscribe() but calls onCompleted() instead! Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subscription – control the lifecycle (global) Manually on the global, Application level – create when you want, and unsubscribe? Never, so do the transactions atomically, close the observables and unsubscribe from activities/fragments: public class SplashActivity extends AppCompatActivity { Subscription mUserSubscription = Subscriptions.empty(); @Override protected void onCreate(Bundle savedInstanceState) { mUserManager.getUserObservable() .subscribe(user -> continue(), throwable -> showError(throwable)); } protected void onDestroy() { if (!mUserSubscription.isUnsubscribed()) mUserSubscription.unsubscribe(); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Subscription – control the lifecycle (global, cont'd) public UserManager () { //from() will automatically call onCompleted() so no pending references Observable.from(loadUserFromSavedPreferences()) .subscribe(user -> mUserSubject.onNext(user), throwable -> mUserSubject.onError(throwable)); } Observable<User> getUserObservable() { return mUserSubject.asObservable(); There's no automated way to manage lifecycle on the global level! Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Architecture example (bound to App context) Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Manager example (bound to App context) loads a configuration, then loads a saved user, and propagates it: public UserManager () { public UserManager() { mConfigurationManager.getCurrentConfigObservable() .flatMap(config -> loadUserFromSavedPreferences()) .subscribe(user -> mUserSubject.onNext(user), throwable -> mUserSubject.onError(throwable)); } Observable<User> getUserObservable() { return mUserSubject.asObservable(); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Manager example - error handling sending onError() closes the subscription and no more events are sent! onError() handles ALL errors in the chain! to prevent this, use error handling methods: onErrorReturn() - use other value onErrorResumeNext() - use other observable onExceptionResumeNext() - handles Exceptions but not Throwables mConfigurationManager.getCurrentConfigObservable() .onErrorReturn(config -> Config.Empty) .flatMap(config -> loadUserFromSavedPreferences()) .onErrorReturn(user -> User.Empty) .subscribe(user -> mUserSubject.onNext(user); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Manager example - splitting subscriptions the whole of the chain is an Observable until the subscribe() if you don’t use error management (onErrorReturn()/onErrorResumeNext()…), all subscriptions have to have onError()– but that is always a good idea!!! Observable<Config) configObservable = mConfigurationManager.getCurrentConfigObservable() .onErrorReturn(config -> Config.Empty); Subscription configValidSub = configObservable .filter(config -> config != null && config != Config.Empty) .flatMap(config -> loadUserFromSavedPreferences()) .onErrorReturn(user -> User.Empty) .subscribe(user -> mUserSubject.onNext(user)); Subscription configInvalidSub = configObservable .filter(config -> config == null || config == Config.Empty) .subscribe(config -> Log.d("App", "config empty!"); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Manager example - reusing observable chains if you have a part of the chain that repeats itself – extract it in a Transformer<T, R> () Subscription configValidUserValidSub = configObservable .filter(config -> config != null && config != Config.Empty) .flatMap(config -> loadUserFromSavedPreferences()) .onErrorReturn(user -> User.Empty) .filter(user -> user != User.Empty) .subscribe(user -> mUserSubject.onNext(user)); Subscription configValidUserInalidSub = configObservable .filter(user -> user == User.Empty) .subscribe(user -> Log.d("APP", "user empty!"); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Manager example - reusing observable chains (cont'd) Observable.Transformer<Config, User> convertConfigToUser() { return new Observable.Transformer<Config, User>() { @Override public Observable<User> call(Observable<Config> configObservable) { return configObservable .filter(config -> config != null && config != Config.Empty) .flatMap(config -> loadUserFromSavedPreferences()) .onErrorReturn(user -> User.Empty); } }; Subscription configValidUserValidSub = configObservable .compose(convertConfigToUser()) .filter(user -> user != User.Empty) .subscribe(user -> mUserSubject.onNext(user)); Subscription configValidUserInalidSub = configObservable .filter(user -> user == User.Empty) .subscribe(user -> Log.d("APP", "user empty!"); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Manager example - multithreading RxJava is asynchronous by default, but not multithreaded by default! use explicit methods to change the thread: subscribeOn() – it changes the upstream thread (until that point) observeOn() – it changes the downstream thread (after that point) Observable.Transformer<Config, User> convertConfigToUser() { return new Observable.Transformer<Config, User>() { @Override public Observable<User> call(Observable<Config> configObservable) { return configObservable .filter(config -> config != null && config != Config.Empty) .flatMap(config -> loadUserFromSavedPreferences()) .onErrorReturn(user -> User.Empty) .subscribeOn(Schedulers.io()) //everything up to this uses io() thread .observeOn(AndroidSchedulers.mainThread()); // everything after this // uses UI thread } }; Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Multithreading – subscribeOn vs observeOn subscribeOn() – it changes the upstream thread (until that point) observeOn() – it changes the downstream thread (after that point) Observable.fromCallable(()-> doSomething1(); //executed on IO thread //if there's no subscribeOn(), execs on calling thread ) .subscribeOn(Schedulers.io()) .filter(something -> doSomething2()) //subscribe call AND everything up to this uses io() thread .observeOn(Schedulers.computation()); //changes thread to computation! .flatMap(something -> doSomething3()) .onErrorReturn(user -> User.Empty) .subscribeOn(Schedulers.computation()) //doesn't matter!!! wasteful! .observeOn(AndroidSchedulers.mainThread()) //switches to UI thread .subscribe(result -> doSomething4()); Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Manager example - multithreading (cont'd) RxJava Scheduler: computation() – bound (limited by CPU cores) io() - unbound immediate() – executes immediately on current thread trampoline() – executes after finishing, on current thread newThread() – creates new thread from(Executor) – use custom executor test() – uses TestScheduler with manual scheduling controls rxandroid library: AndroidScheduler.mainThread() Multithreading is hard, RxJava makes it easier – but it's still not easy! do not specify the thread unless you really need to Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic

Further reading/watching https://github.com/ReactiveX/RxJava RxJava Single discussion: https://github.com/ReactiveX/RxJava/issues/1594 RxJava Subscriber discussion: https://github.com/ReactiveX/RxJava/issues/792 New viewbinding library using RxJava: https://github.com/alter-ego/androidbound ReactiveX homepage: http://reactivex.io/ Interactive marble diagrams for operators: http://www.rxmarbles.com/ Ben Christensen's talks: https://speakerdeck.com/benjchristensen/ David Karnok's Advanced RxJava blog: http://akarnokd.blogspot.hu/ Grokking Rx MEAP: http://bit.ly/grokking-rx Recipes in RxJava for Android | #GrokkingRx | @sasa_sekulic