Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Reactive programming on Android

6,700 views

Published on

Lecture on Reactive programming on Android. DevFest Prague 2014.

Published in: Technology
  • Android Programming for Beginners --- http://amzn.to/1pCkwYW
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Android Programming: The Big Nerd Ranch Guide (2nd Edition) --- http://amzn.to/1Sb2qX5
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Android Programming In a Day!: The Power Guide for Beginners In Android App Programming --- http://amzn.to/1pCku3q
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Reactive programming on Android

  1. 1. Reactive programming on Android Tomáš Kypta
  2. 2. What’s reactive programming? reactive programming or functional reactive programming (FRP)
  3. 3. What’s reactive programming? functional – lambdas – closures – pure – composable reactive – data flow – asynchronous – values – events – push
  4. 4. Reactive? • observer pattern
  5. 5. Typical App Event Source Views Network DB Other Listener Listener Listener Listener logic logic logic logic State
  6. 6. Views Network DB Transformation Reactive Event Source Other Observable Observable Observable Observable Observer Observer
  7. 7. Reactive • abstract away from concerns about – low-level threading – side effects – synchronization – encapsulation – resource management
  8. 8. Java 8 Observable.toObservable(“a”, “b”, “c”) .take(2) .subscribe((arg) -> { System.out.println(arg); }); Reactive Code
  9. 9. Reactive on Android • evading callback hell • How to execute heavy tasks on background threads? • And deliver results on the main (UI) thread?
  10. 10. Async on Android
  11. 11. Handler handler = new Handler(); new Thread(){ @Override public void run() { final String result = somethingDemanding(); handler.post(new Runnable() { @Override public void run() { showResult(result); } }); } }.start(); Thread + Handler
  12. 12. Handler handler = new Handler(); new Thread(){ @Override public void run() { final String result = somethingDemanding(); handler.post(new Runnable() { @Override public void run() { showResult(result); } }); } }.start(); Thread + Handler
  13. 13. Thread + Handler • simple • difficult to deliver on the main thread • broken data flow
  14. 14. new AsyncTask<Void, Integer, String>(){ @Override protected String doInBackground(Void... params) { return somethingDemanding(); } @Override protected void onPostExecute(String s) { showResult(s); } }.execute(); AsyncTask
  15. 15. AsyncTask • deals with the main thread • error-prone • difficult error propagation • difficult to bound to activity/fragment lifecycle • difficult composition
  16. 16. class MyFragment extends Fragment implements LoaderManager.LoaderCallbacks<String> { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getLoaderManager().initLoader(42, null, this); } @Override public Loader<String> onCreateLoader(int id, Bundle args) { return new AsyncTaskLoader<String>(getActivity()) { @Override public String loadInBackground() { return doHeavyTask(); } }; } @Override public void onLoadFinished(Loader<String> loader, String data) { showResult(data); } @Override public void onLoaderReset(Loader<String> loader) {} } Loaders
  17. 17. Loaders
  18. 18. Loaders • boilerplate • good for cursors • deals with activity/fragment lifecycle • difficult composition • difficult to adjust logic
  19. 19. Async on Android • many other async libraries – some are better – some are worse
  20. 20. RxJava
  21. 21. RxJava • Java VM implementation of Reactive Extensions • a library for composing flows and sequences of asynchronous data • open-source • https://github.com/ReactiveX/RxJava • by Netflix
  22. 22. RxJava • DSL for creating computation flows from async sources • flows called Observables • push semantics of Observables
  23. 23. RxJava … not sure if …
  24. 24. Future proxy or wrapper around an object that is not yet there future.get() future.isDone() • non-trivial complexity when nested • difficult to compose conditional asynchronous execution flows
  25. 25. Iterable vs. Observable
  26. 26. Iterable vs. Observable // Iterable<String> getData() .skip(10) .take(5) .map({s -> return s + “1”}) .forEach({ println it }); // Observable<String> getData() .skip(10) .take(5) .map({s -> return s + “1”}) .subscribe({ println it });
  27. 27. Iterable vs. Observable single items multiple items synchronous T getData() Iterable<T> getData() asynchronous Future<T> getData() Observable<T> getData()
  28. 28. Iterable vs. Observable event Iterable (pull) Observable (push) retrieve data T next() onNext(T) discover error throws Exception onError(Exception) complete !hasNext() onCompleted()
  29. 29. Observable Calling Thread public Observable<String> getData(); Callback Thread synchronous on calling thread
  30. 30. Observable Calling Thread public Observable<String> getData(); Callback Thread Thread Pool asynchronous on a separate thread
  31. 31. Observable Calling Thread public Observable<String> getData(); Callback Threads Thread Pool asynchronous on multiple threads
  32. 32. Observable • not biased toward some particular source of asynchronicity • the implementation chooses if the code will be blocking or non-blocking
  33. 33. public interface Observer <T> { void onCompleted(); void onError(Throwable throwable); void onNext(T t); } Observable
  34. 34. public Observable<String> getStrings() { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { try { subscriber.onNext("Hello"); subscriber.onNext("World"); subscriber.onCompleted(); } catch (Exception ex) { subscriber.onError(ex); } } }); } Observable
  35. 35. Observable<String> strings = getStrings(); strings.subscribe( new Observer<String>() { @Override public void onCompleted() { Log.d("rx", "no more data"); } @Override public void onError(Throwable throwable) { Log.e(“rx”, “error”, throwable); } @Override public void onNext(String s) { showResult(s); } }); Observer
  36. 36. Observable<String> strings = getStrings(); strings.subscribe( new Observer<String>() { @Override public void onCompleted() { Log.d("rx", "no more data"); } @Override public void onError(Throwable throwable) { Log.e(“rx”, “error”, throwable); } @Override public void onNext(String s) { showResult(s); } }); Observer
  37. 37. Observable<String> strings = getStrings(); strings.subscribe( new Observer<String>() { @Override public void onCompleted() { Log.d("rx", "no more data"); } @Override public void onError(Throwable throwable) { Log.e(“rx”, “error”, throwable); } @Override public void onNext(String s) { showResult(s); } }); Observer
  38. 38. Observable<String> strings = getStrings(); strings.subscribe( new Observer<String>() { @Override public void onCompleted() { Log.d("rx", "no more data"); } @Override public void onError(Throwable throwable) { Log.e(“rx”, “error”, throwable); } @Override public void onNext(String s) { showResult(s); } }); Observer
  39. 39. Observable<String> strings = getStrings(); Subscription subsctiption = strings.subscribe( new Observer<String>() { @Override public void onCompleted() { Log.d("rx", "no more data"); } @Override public void onError(Throwable throwable) { Log.e(“rx”, “error”, throwable); } @Override public void onNext(String s) { showResult(s); } }); Observer
  40. 40. Subscription Subscription subsctiption; subscription.unsubscribe(); subscription.isUnsubscribed();
  41. 41. Android & RxJava
  42. 42. RxAndroid Android specific things for Rx • Scheduler • reliable and thread-safe with regarding Fragment/Activity life-cycle • reactive components for Android use cases and UI
  43. 43. RxAndroid • https://github.com/ReactiveX/RxAndroid • 'io.reactivex:rxandroid:0.23.0' • formerly rxjava-android
  44. 44. Image Loading Observable<Bitmap> imageObservable = Observable.create(observer -> { return downloadBitmap(); }); imageObservable .subscribe(image -> loadToImageView(image));
  45. 45. Image Loading Observable<Bitmap> imageObservable = Observable.create(observer -> { return downloadBitmap(); }); imageObservable .subscribe(image -> loadToImageView(image));
  46. 46. Image Loading imageObservable .subscribeOn(Schedulers.newThread()) .subscribe(image -> loadToImageView(image));
  47. 47. Image Loading imageObservable .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(image -> loadToImageView(image));
  48. 48. Image Loading imageObservable .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(image -> loadToImageView(image));
  49. 49. public void onDestroy() { super.onDestroy(); subscription.unsubscribe(); } Lifecycle & Memory Leaks
  50. 50. Fragment/Activity Lifecycle ContentObservable .bindFragment(fragment, observable); ContentObservable .bindActivity(activity, observable);
  51. 51. Broadcast Receiver Observable<Intent> observable = ContentObservable .fromBroadcast(context, intentFilter); Observable<Intent> observable = ContentObservable .fromLocalBroadcast(context, intentFilter);
  52. 52. Views Observable<OnClickEvent> observable = ViewObservable.clicks(view); ViewObservable .bindView(view, observable);
  53. 53. Creating Observables
  54. 54. Creating Observables • manually from scratch create()
  55. 55. Creating Observables • convert existing data structure into an Observable from() – Iterable, Future, Array repeat() – emit source Observable repeatedly
  56. 56. Creating Observables • convert existing data structure into an Observable timer() – emits a single item after a given time
  57. 57. Creating Observables • convert existing data structure into an Observable empty() – emits nothing and completes error() – emits nothing and signals an error never() – emits nothing at all
  58. 58. Obervables are composable transform - map, flatMap, reduce, scan filter - take, skip, sample, filter combine - concat, merge, zip, cache concurrency - observeOn, subcribeOn error handling - onErrorReturn
  59. 59. Transforming Observables
  60. 60. Transforming Observables map() – apply a function to each item
  61. 61. Transforming Observables flatMap() – transform items into Observables and flatten
  62. 62. Transforming Observables scan() – apply a function to each item sequentially and emit each successive value
  63. 63. Transforming Observables groupBy() – divide into a set of Observables
  64. 64. Transforming Observables buffer() – periodically gather items into bundles and emits these bundles
  65. 65. Filtering Observables
  66. 66. Filtering Observable filter() – filter emitted items
  67. 67. Filtering Observable take() – emit only first n items
  68. 68. Filtering Observable timeout() – emit items, but issue an exception if nothing emitted in a timespan
  69. 69. Filtering Observable distinct() – suppress duplicate items
  70. 70. Filtering Observable takeLastBuffer() first() elementAt() – emit only n-th element ignoreElements() – pass only error or completed
  71. 71. Combining Observables
  72. 72. Combining Observables merge() – combine multiple Observables
  73. 73. Combining Observables zip() – combine multiple Observables via a function, emit results of the function
  74. 74. Error Handling
  75. 75. Error Handling recovering from onError() onErrorResumeNext() – emit a sequence if error happens
  76. 76. Error Handling onErrorReturn() – emit an item if error happens
  77. 77. Error Handling retry() – resubscribe to a source
  78. 78. Support for RxJava in other libraries
  79. 79. Retrofit @GET("/user/{id}/photo") Observable<Photo> getUserPhoto(@Path("id") int id);
  80. 80. private Object simpleMethod() { ... } public Observable<Object> newMethod() { return Observable.just(simpleMethod()); } Plain old library
  81. 81. private Object simpleMethod() { ... } public Observable<Object> newMethod() { return Observable.defer(() -> Observable.just(simpleMethod()) ); } Plain old library
  82. 82. Java 8 & Android No lambdas on Android – use different language on Android – or rather not
  83. 83. Retrolambda transforms Java 8 compiled bytecode for older JVM • gradle-retrolambda – https://github.com/evant/gradle-retrolambda – 'me.tatarka:gradle-retrolambda:2.4.1' • retrolambda – https://github.com/orfjackal/retrolambda
  84. 84. strings.map(new Func1<String, Integer>() { @Override public Integer call(String s) { return s.length(); } }); Without Retrolambda
  85. 85. strings.map( (String s) -> { return s.length(); } ); With Retrolambda
  86. 86. Problems • RxAndroid APIs not yet stabilized even though RxJava hitting version 1.0 – RxAndroid version 0.23 • backpressure
  87. 87. Questions?
  88. 88. THE END

×