Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxApplications

 RxApplications

A talk that gets into the basics of using RxJava for observing asynchronous events including user input, network responses, and the result of database interactions.

A2ca9534b32c7dbf57b3142ad9884f15?s=128

Kevin Carpenter

April 22, 2017
Tweet

More Decks by Kevin Carpenter

Other Decks in Programming

Transcript

  1. RxApplications Kevin Carpenter Notion AI

  2. Application behavior is asynchronous.

  3. Pull to Refresh

  4. GET https://hacker-news.firebaseio.com/v0/items [{ "by": "jamesblonde", "descendants": 0, "id": 11595667, "score":

    2, "time": 1461937655, "title": “Make email great again”, "type": "story", "url": “https:\/\/email.net/great” }]
  5. INSERT INTO items (title, author, points, date)
 VALUES (‘Rx’, ‘kevcar’,

    90, 1492278237562)
  6. DELETE FROM items WHERE date < 1492278000 AND date >

    1492280000
  7. None
  8. None
  9. ☝ swipeRefreshLayout.setOnRefreshListener( new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() {

    // make update request } } );
  10. RxJava

  11. RxJava RxJS

  12. RxJava RxJS RxKotlin

  13. RxJava RxJS RxKotlin RxSwift

  14. “ReactiveX is a combination of the best ideas from the

    Observer pattern, the Iterator pattern, and functional programming”
  15. abstract class Observer<T> { 
 fun update(T notification) 
 }

  16. abstract class Observable<T> { 
 private val ArrayList<Observer<T>> observers; 


    
 fun registerObserver(Observer<T> observer) { 
 observers.add(observer); 
 } 
 
 fun unregisterObserver(Observer<T> observer) { 
 observers.remove(observer); 
 } 
 } 

  17. abstract class Observable<T> { 
 private val observers: ArrayList<Observer<T>> 


    
 fun registerObserver(observer: Observer<T>) { 
 observers.add(observer); 
 } 
 
 fun unregisterObserver(observer: Observer<T>) { 
 observers.remove(observer); 
 } 
 } 

  18. abstract class Observable<T> { 
 private val observers: ArrayList<Observer<T>>
 


    void registerObserver(observer: Observer<T>) { 
 observers.add(observer) 
 } 
 
 void unregisterObserver(observer: Observer<T>) { 
 observers.remove(observer);
 } 
 
 void setValue(newValue: T) { 
 this.value = newValue
 notifyObservers(newValue)
 } 
 } 

  19. abstract class Observable<T> { 
 private val observers: ArrayList<Observer<T>> ;

    
 
 fun registerObserver(observer: Observer<T>) { 
 observers.add(observer); 
 } 
 
 fun unregisterObserver(observer: Observer<T>) { 
 observers.remove(observer); 
 } 
 
 fun setValue(newValue: T) { 
 this.value = newValue; 
 notifyObservers(newValue); 
 } 
 
 fun notifyObservers(value: T) { 
 for (observer : observers) { 
 observer.update(value); 
 } 
 } 
 }
  20. “ReactiveX is a combination of the best ideas from the

    Observer pattern, the Iterator pattern, and functional programming”
  21. interface Iterable<T> 
 
 fun iterator(): Iterator<T> 
 
 }

  22. interface Iterator<T> 
 
 fun hasNext(): Boolean 
 
 fun

    next(): T 
 
 }
  23. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 while (sounds.iterator().hasNext()) { 
 log.d("Animal Sound", sounds.next()) 
 }
  24. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 while (sounds.iterator().hasNext()) { 
 log.d("Animal Sound", sounds.next()) 
 } D/Animal Sound: moo
  25. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 while (sounds.iterator().hasNext()) { 
 log.d("Animal Sound", sounds.next()) 
 } D/Animal Sound: moo D/Animal Sound: cluck
  26. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 while (sounds.iterator().hasNext()) { 
 log.d("Animal Sound", sounds.next()) 
 } D/Animal Sound: moo D/Animal Sound: cluck D/Animal Sound: quack

  27. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 sounds.map { sound -> 
 sound + sound // "$sound $sound" 
 } 
 .map { doubleSound -> 
 log.d("Animal Sound", doubleSound) 
 }
  28. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 sounds.map { sound -> 
 sound + sound // "$sound $sound" 
 } 
 .map { doubleSound -> 
 log.d("Animal Sound", doubleSound) 
 } D/Animal Sound: moo moo

  29. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 sounds.map { sound -> 
 sound + sound // "$sound $sound" 
 } 
 .map { doubleSound -> 
 log.d("Animal Sound", doubleSound) 
 } D/Animal Sound: moo moo D/Animal Sound: cluck cluck
  30. val sounds: Iterable<String> = listOf( "moo", "cluck", “quack" ) 


    
 sounds.map { sound -> 
 sound + sound // "$sound $sound" 
 } 
 .map { doubleSound -> 
 log.d("Animal Sound", doubleSound) 
 } D/Animal Sound: moo moo D/Animal Sound: cluck cluck D/Animal Sound: quack quack

  31. “ReactiveX is a combination of the best ideas from the

    Observer pattern, the Iterator pattern, and functional programming”
  32. f(x) = y

  33. { x -> x * x; }

  34. int square(int x) { 
 int square = x *

    x; 
 textView.text = square; 
 return result; 
 } 

  35. int square(int x) { 
 int square = x *

    x; 
 this.state.latestSquare = square; 
 return result; 
 } 

  36. // 1, 2, 3
 Observable<Integer> intObservable = Observable.range(1, 4) 


    
 intObservable.map { x -> 
 x * x 
 } 
 .map { squared -> 
 "Result: " + squared 
 } 
 .map { str -> 
 log.d(str) 
 }
  37. Observable

  38. time

  39. time

  40. time

  41. Observable.from(listOf<String>("moo", "cluck", "quack")) time

  42. Observable.from(listOf<String>("moo", "cluck", "quack")) time moo

  43. Observable.from(listOf<String>("moo", "cluck", "quack")) time moo cluck

  44. Observable.from(listOf<String>("moo", "cluck", "quack")) time moo cluck quack

  45. time moo cluck X

  46. time moo X

  47. time moo cluck

  48. Observable.subscribe( Subscriber<T> subscriber )

  49. abstract class Subscriber<T> { 
 onNext(T t); 
 onError(Throwable e);

    // Terminal 
 onCompleted(); // Terminal 
 } 

  50. abstract class Subscriber<T> { 
 onNext(T t); 
 onError(Throwable e);

    // Terminal 
 onCompleted(); // Terminal 
 } 
 
 Observable.subscribe( 
 Action1<T> onNext, 
 Action1<Throwable>, onError, 
 Action0 onCompleted) 

  51. val action = Action1<String> { 
 fun event (event: String)

    { 
 log.d("Animal Sound", event) 
 } 
 } 
 
 val errorAction = Action1<Throwable> { 
 fun event (event: Throwable) { 
 log.e(event, "Error in Animal Sounds Example") 
 } 
 } 
 
 val completedAction = Action0 { 
 fun call { 
 log.d("Completed Event", "Animal Sounds are done.") 
 } 
 } 
 
 observable.subscribe(action, errorAction, completedAction)
  52. val action = Action1<String> { 
 fun event (event: String)

    { 
 log.d("Animal Sound", event) 
 } 
 } 
 
 val errorAction = Action1<Throwable> { 
 fun event (event: Throwable) { 
 log.e(event, "Error in Animal Sounds Example") 
 } 
 } 
 
 val completedAction = Action0 { 
 fun call { 
 log.d("Completed Event", "Animal Sounds are done.") 
 } 
 } 
 
 observable.subscribe(action, errorAction, completedAction)
  53. val action = Action1<String> { 
 fun event (event: String)

    { 
 log.d("Animal Sound", event) 
 } 
 } 
 
 val errorAction = Action1<Throwable> { 
 fun event (event: Throwable) { 
 log.e(event, "Error in Animal Sounds Example") 
 } 
 } 
 
 val completedAction = Action0 { 
 fun call { 
 log.d("Completed Event", "Animal Sounds are done.") 
 } 
 } 
 
 observable.subscribe(action, errorAction, completedAction)
  54. val action = Action1<String> { 
 fun event (event: String)

    { 
 log.d("Animal Sound", event) 
 } 
 } 
 
 val errorAction = Action1<Throwable> { 
 fun event (event: Throwable) { 
 log.e(event, "Error in Animal Sounds Example") 
 } 
 } 
 
 val completedAction = Action0 { 
 fun call { 
 log.d("Completed Event", "Animal Sounds are done.") 
 } 
 } 
 
 observable.subscribe(action, errorAction, completedAction)
  55. Observable.from(listOf<String>("moo", "cluck", “quack")) time

  56. Observable.from(listOf<String>("moo", "cluck", “quack")) time moo D/Animal Sound: moo

  57. Observable.from(listOf<String>("moo", "cluck", “quack")) time moo cluck D/Animal Sound: moo D/Animal

    Sound: cluck
  58. Observable.from(listOf<String>("moo", "cluck", “quack")) time moo cluck quack D/Animal Sound: moo

    D/Animal Sound: cluck D/Animal Sound: quack
  59. Observable.from(listOf<String>("moo", "cluck", “quack")) time moo cluck quack D/Animal Sound: moo

    D/Animal Sound: cluck D/Animal Sound: quack D/Completed Event: Animal Sounds are Done
  60. Observable.from(listOf<String>("moo", "cluck", “quack")) time moo cluck D/Animal Sound: moo D/Animal

    Sound: cluck E/Error Event: Error in Animal Sounds example at com.rxapplications.example.ExampleClass… X
  61. Non-RxViews

  62. Pull to Refresh

  63. class ItemListView : FrameLayout, IItemListView { 
 
 @Inject 


    private val model: ItemListViewModel 
 
 private val refreshView by bindView<SwipeRefreshLayout>(R.id.swipe_view) 
 private val adapter = ItemListViewAdapter(context) 
 
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } 
 
 private val listener = object : SwipeRefreshLayout.OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } }
  64. class ItemListView : FrameLayout, IItemListView { 
 
 @Inject 


    private val model: ItemListViewModel 
 
 private val refreshView by bindView<SwipeRefreshLayout>(R.id.swipe_view) 
 private val adapter = ItemListViewAdapter(context) 
 
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } 
 
 private val listener = object : SwipeRefreshLayout.OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } }
  65. class ItemListView : FrameLayout, IItemListView { 
 
 @Inject 


    private val model: ItemListViewModel 
 
 private val refreshView by bindView<SwipeRefreshLayout>(R.id.swipe_view) 
 private val adapter = ItemListViewAdapter(context) 
 
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } 
 
 private val listener = object : SwipeRefreshLayout.OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } }
  66. class ItemListView : FrameLayout, IItemListView { 
 
 @Inject 


    private val model: ItemListViewModel 
 
 private val refreshView by bindView<SwipeRefreshLayout>(R.id.swipe_view) 
 private val adapter = ItemListViewAdapter(context) 
 
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } 
 
 private val listener = object : SwipeRefreshLayout.OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } }
  67. class ItemListView : FrameLayout, IItemListView { 
 // Set up


    
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } }
  68. class ItemListView : FrameLayout, IItemListView { 
 // Set up


    
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } }
  69. class ItemListView : FrameLayout, IItemListView { 
 // Set up


    
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } }
  70. interface IItemListView { 
 
 fun onItemsResponse(items: List<Item>) 
 


    fun onItemsError(error: Throwable) 
 
 fun onRefreshComplete() 
 } 
 

  71. interface IItemListView { 
 
 fun onItemsResponse(items: List<Item>) 
 


    fun onItemsError(error: Throwable) 
 
 fun onRefreshComplete() 
 } 
 

  72. interface IItemListView { 
 
 fun onItemsResponse(items: List<Item>) 
 


    fun onItemsError(error: Throwable) 
 
 fun onRefreshComplete() 
 } 
 

  73. class ItemListView : FrameLayout, IItemListView { 
 // Set up


    
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } private val listener = object : OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } }
  74. class ItemListView : FrameLayout, IItemListView { 
 // Set up


    
 override fun onFinishInflate() { 
 super.onFinishInflate() 
 refreshView.setOnRefreshListener(listener) 
 } 
 
 override fun onAttachedToWindow() { 
 super.onAttachedToWindow() 
 model.attach(this) 
 } 
 
 override fun onDetachedFromWindow() { 
 model.detach(this) 
 super.onDetachedFromWindow() 
 } private val listener = object : OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } }
  75. class ItemListView : FrameLayout, IItemListView { 
 
 private val

    listener = object : OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } 
 
 override fun onItemsResponse(items: List<Item>) { 
 adapter.setItems(items) 
 } 
 
 override fun onItemsError(error: Throwable) { 
 log.e(error, "Error in ItemListView") 
 } 
 
 override fun onRefreshComplete() { 
 refreshView.setRefreshing(false) 
 } 
 
 }
  76. class ItemListView : FrameLayout, IItemListView { 
 
 private val

    listener = object : OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } 
 
 override fun onItemsResponse(items: List<Item>) { 
 adapter.setItems(items) 
 } 
 
 override fun onItemsError(error: Throwable) { 
 log.e(error, "Error in ItemListView") 
 } 
 
 override fun onRefreshComplete() { 
 refreshView.setRefreshing(false) 
 } 
 
 }
  77. class ItemListView : FrameLayout, IItemListView { 
 
 private val

    listener = object : OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } 
 
 override fun onItemsResponse(items: List<Item>) { 
 adapter.setItems(items) 
 } 
 
 override fun onItemsError(error: Throwable) { 
 log.e(error, "Error in ItemListView") 
 } 
 
 override fun onRefreshComplete() { 
 refreshView.setRefreshing(false) 
 } 
 
 }
  78. class ItemListView : FrameLayout, IItemListView { 
 
 private val

    listener = object : OnRefreshListener { 
 override fun onRefresh() { 
 model.requestRefresh() 
 } 
 } 
 
 override fun onItemsResponse(items: List<Item>) { 
 adapter.setItems(items) 
 } 
 
 override fun onItemsError(error: Throwable) { 
 log.e(error, "Error in ItemListView") 
 } 
 
 override fun onRefreshComplete() { 
 refreshView.setRefreshing(false) 
 } 
 
 }
  79. interface IItemListView { 
 
 fun onItemsResponse(items: List<Item>) fun onItemsError(error:

    Throwable)
 
 fun onRefreshComplete()
 } 
 

  80. interface IItemListView { 
 
 fun onItemsResponse(items: List<Item>) fun onItemsError(error:

    Throwable)
 
 fun onRefreshComplete() fun onNextResponsePage(items: List<Item>) fun onNextResponsePageError(error: Throwable)
 
 fun onNextResponsePageComplete()
 } 
 

  81. RxViews

  82. Pull to Refresh

  83. class ItemListView : FrameLayout { 
 
 @Inject 
 private

    val model: ItemListViewModel 
 private val subscriptions = CompositeSubscription() 
 
 private val refreshView by bindView<SwipeRefreshLayout>(R.id.swipe) 
 private val adapter = ItemListViewAdapter(context) 
 } 
 

  84. class ItemListView : FrameLayout { 
 
 @Inject 
 private

    val model: ItemListViewModel 
 private val subscriptions = CompositeSubscription() 
 
 private val refreshView by bindView<SwipeRefreshLayout>(R.id.swipe) 
 private val adapter = ItemListViewAdapter(context) 
 } 
 

  85. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 subscriptions.add( 
 swipeRefreshLayout.refreshes() 
 .subscribe(refreshObserver) 
 ) 
 
 model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(responseObserver) 
 
 } 
 }
  86. RxBinding

  87. final class SwipeRefreshLayoutRefreshObservable extends Observable<Object> { 
 private final SwipeRefreshLayout

    view; 
 
 SwipeRefreshLayoutRefreshObservable(SwipeRefreshLayout view) { 
 this.view = view; 
 } 
 
 @Override protected void subscribeActual( Observer<? super Object> observer) { 
 if (!checkMainThread(observer)) { 
 return; 
 } 
 Listener listener = new Listener(view, observer); 
 observer.onSubscribe(listener); 
 view.setOnRefreshListener(listener); 
 }
  88. final class SwipeRefreshLayoutRefreshObservable extends Observable<Object> { 
 private final SwipeRefreshLayout

    view; 
 
 SwipeRefreshLayoutRefreshObservable(SwipeRefreshLayout view) { 
 this.view = view; 
 } 
 
 @Override protected void subscribeActual( Observer<? super Object> observer) { 
 if (!checkMainThread(observer)) { 
 return; 
 } 
 Listener listener = new Listener(view, observer); 
 observer.onSubscribe(listener); 
 view.setOnRefreshListener(listener); 
 }
  89. final class SwipeRefreshLayoutRefreshObservable extends Observable<Object> { 
 private final SwipeRefreshLayout

    view; 
 
 SwipeRefreshLayoutRefreshObservable(SwipeRefreshLayout view) { 
 this.view = view; 
 } 
 
 @Override protected void subscribeActual( Observer<? super Object> observer) { 
 if (!checkMainThread(observer)) { 
 return; 
 } 
 Listener listener = new Listener(view, observer); 
 observer.onSubscribe(listener); 
 view.setOnRefreshListener(listener); 
 }
  90. final class SwipeRefreshLayoutRefreshObservable extends Observable<Object> { 
 private final SwipeRefreshLayout

    view; 
 
 SwipeRefreshLayoutRefreshObservable(SwipeRefreshLayout view) { 
 this.view = view; 
 } 
 
 @Override protected void subscribeActual( Observer<? super Object> observer) { 
 if (!checkMainThread(observer)) { 
 return; 
 } 
 Listener listener = new Listener(view, observer);
 observer.onSubscribe(listener); 
 view.setOnRefreshListener(listener); 
 }
  91. static final class Listener extends MainThreadDisposable implements OnRefreshListener { 


    private final SwipeRefreshLayout view; 
 private final Observer<? super Object> observer; 
 
 @Override public void onRefresh() { 
 if (!isDisposed()) { 
 observer.onNext(Notification.INSTANCE); 
 } 
 } 
 
 @Override protected void onDispose() { 
 view.setOnRefreshListener(null); 
 } 
 } 

  92. static final class Listener extends MainThreadDisposable implements OnRefreshListener { 


    private final SwipeRefreshLayout view; 
 private final Observer<? super Object> observer; 
 
 @Override public void onRefresh() { 
 if (!isDisposed()) { 
 observer.onNext(Notification.INSTANCE); 
 } 
 } 
 
 @Override protected void onDispose() { 
 view.setOnRefreshListener(null); 
 } 
 } 

  93. static final class Listener extends MainThreadDisposable implements OnRefreshListener { 


    private final SwipeRefreshLayout view; 
 private final Observer<? super Object> observer; 
 
 @Override public void onRefresh() { 
 if (!isDisposed()) { 
 observer.onNext(Notification.INSTANCE); 
 } 
 } 
 
 @Override protected void onDispose() { 
 view.setOnRefreshListener(null); 
 } 
 } 

  94. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 subscriptions.add( 
 swipeRefreshLayout.refreshes() 
 .subscribe(refreshObserver) 
 ) 
 
 subscriptions.add( 
 model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(responseObserver) 
 ) 
 } 
 } 
 

  95. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 subscriptions.add( 
 swipeRefreshLayout.refreshes() 
 .subscribe(refreshObserver) 
 ) 
 
 subscriptions.add( 
 model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(responseObserver) 
 ) 
 } 
 } 
 

  96. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 subscriptions.add( 
 swipeRefreshLayout.refreshes() 
 .subscribe(refreshObserver) 
 ) 
 
 subscriptions.add( 
 model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(responseObserver) 
 ) 
 } private val refreshObserver = { refresh: Unit -> 
 model.refreshMessages() 
 }
 } 
 

  97. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 subscriptions.add( 
 swipeRefreshLayout.refreshes() 
 .subscribe(refreshObserver) 
 ) 
 
 subscriptions.add( 
 model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(responseObserver) 
 ) 
 } 
 } 
 

  98. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 subscriptions.add( 
 swipeRefreshLayout.refreshes() 
 .subscribe(refreshObserver) 
 ) 
 
 subscriptions.add( 
 model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(responseObserver) 
 ) 
 } 
 } 
 

  99. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() /* Subscriptions defined here.*/
 } private val responseObserver = { response: Response<ItemListResponse> -> 
 if (response.isSuccess()) { 
 adapter.setItems(response.items) 
 } 
 else { val error = /* Pull Throwable from response */
 log.e(error, "Error in ItemListView") 
 } 
 //refreshView.setRefreshing(false)
 refreshView.refreshing = false
 }
 }
  100. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() /* Subscriptions defined here.*/
 } private val responseObserver = { response: Response<ItemListResponse> -> 
 if (response.isSuccess()) { 
 adapter.setItems(response.items) 
 } 
 else { 
 val error = /* Pull Throwable from response */
 log.e(error, "Error in ItemListView")
 } 
 //refreshView.setRefreshing(false)
 refreshView.refreshing = false
 }
 }
  101. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() /* Subscriptions defined here.*/
 } private val responseObserver = { response: Response<ItemListResponse> -> 
 if (response.isSuccess()) { 
 adapter.setItems(response.items) 
 } 
 else { val error = /* Pull Throwable from response */
 log.e(error, "Error in ItemListView") 
 } 
 //refreshView.setRefreshing(false)
 refreshView.refreshing = false
 }
 }
  102. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() /* Subscriptions defined here.*/
 } private val responseObserver = { response: Response<ItemListResponse> -> 
 if (response.isSuccess()) { 
 adapter.setItems(response.items) 
 } 
 else { 
 val error = /* Pull Throwable from response */
 log.e(error, "Error in ItemListView")
 }
 //refreshView.setRefreshing(false)
 refreshView.refreshing = false
 }
 }
  103. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .publish() 
 
 subscriptions.add( 
 responseObservable 
 .filter { it.isSuccessful() } 
 .subscribe(successObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .filter { !it.isSuccessful() } 
 .subscribe(errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(refreshView.refreshing()) // RxBinding! 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .connect() 
 ) 
 }
 } 
 

  104. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = model.observeResponse() 
 .observeOn(AndroidSchedulers.mainThread()) 
 .publish() 
 
 /* subscriptions created here */ subscriptions.add( 
 responseObservable 
 .connect() 
 )
 } } 
 

  105. override fun onAttachedToWindow() { super.onAttachedToWindow() 
 val responseObservable = model.observeResponse()

    
 .observeOn(AndroidSchedulers.mainThread()) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(successObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(errorObserver) 
 ) 
 }
  106. override fun onAttachedToWindow() { super.onAttachedToWindow() 
 val responseObservable = model.observeResponse()

    
 .observeOn(AndroidSchedulers.mainThread()) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(successObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(errorObserver) 
 ) subscriptions.add( 
 responseObservable.connect() 
 )
 }
  107. None
  108. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = // Connectable Observable
 
 subscriptions.add( 
 responseObservable 
 .filter { it.isSuccessful() } 
 .subscribe(successObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .filter { !it.isSuccessful() } 
 .subscribe(errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(refreshView.refreshing()) // RxBinding! 
 ) 
 
 // Connect Observable here
 }
 } 
 

  109. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = // Connectable Observable
 
 subscriptions.add( 
 responseObservable 
 .filter { it.isSuccessful() } 
 .subscribe(successObserver) 
 ) 
 } private val successObserver = { 
 adapter.setItems(response.body) 
 } }
  110. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = // Connectable Observable
 
 subscriptions.add( 
 responseObservable 
 .filter { !it.isSuccessful() } 
 .subscribe(errorObserver) 
 )
 // Connect Observable here
 } private val errorObserver = { 
 val error = /* extract error from response */ 
 log.e(error, "Error in ItemListView") 
 }
 } 
 

  111. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = // Connectable Observable
 
 subscriptions.add( 
 responseObservable 
 .filter { it.isSuccessful() } 
 .subscribe(successObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .filter { !it.isSuccessful() } 
 .subscribe(errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(refreshView.refreshing()) 
 ) 
 
 // Connect Observable here
 }
 } 
 

  112. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = // Connectable Observable
 
 subscriptions.add( 
 responseObservable 
 .filter { it.isSuccessful() } 
 .subscribe(successObserver, errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .filter { !it.isSuccessful() } 
 .subscribe(errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(refreshView.refreshing()) 
 ) 
 
 // Connect Observable here
 }
 } 
 

  113. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = // Connectable Observable
 
 subscriptions.add( 
 responseObservable 
 .filter { it.isSuccessful() } 
 .subscribe(successObserver, errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .filter { !it.isSuccessful() } 
 .subscribe(errorObserver, errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(refreshView.refreshing()) 
 ) 
 
 // Connect Observable here
 }
 } 
 

  114. class ItemListView : FrameLayout { 
 
 override fun onAttachedToWindow()

    { 
 super.onAttachedToWindow() 
 val responseObservable = // Connectable Observable
 
 subscriptions.add( 
 responseObservable 
 .filter { it.isSuccessful() } 
 .subscribe(successObserver, errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .filter { !it.isSuccessful() } 
 .subscribe(errorObserver, errorObserver) 
 ) 
 
 subscriptions.add( 
 responseObservable 
 .subscribe(refreshView.refreshing(), errorObserver) 
 ) 
 
 // Connect Observable here
 }
 } 
 

  115. RxRequests

  116. interface ItemService { 
 @GET("/items") 
 fun getItems(): Response<List<Item>> 


    } 
 

  117. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response>
 
 class Request(val save: Boolean) 
 
 class Response(items: Either<Throwable, List<Item>>) 
 }
  118. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> 
 class Request(val save: Boolean) 
 
 class Response(items: Either<Throwable, List<Item>>) 
 }
  119. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> 
 class Request(val save: Boolean) 
 
 class Response(items: Either<Throwable, List<Item>>) 
 }
  120. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> 
 class Request(val save: Boolean) 
 
 class Response(items: Either<Throwable, List<Item>>) 
 }
  121. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> { 
 return service.getItems() 
 .map { response -> 
 if (response.isSuccessful) { 
 Response(Either.ofRight(response.body)) 
 } 
 else { 
 val error = /* Pull error out of Response */ 
 Response(Either.ofLeft(error)) 
 } 
 } 
 .onErrorReturn { error -> 
 Response(Either.ofLeft(error)) 
 } 
 } 
 }
  122. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> { 
 return service.getItems() 
 .map { response -> 
 if (response.isSuccessful) { 
 Response(Either.ofRight(response.body)) 
 } 
 else { 
 val error = /* Pull error out of Response */ 
 Response(Either.ofLeft(error)) 
 } 
 } 
 .onErrorReturn { error -> 
 Response(Either.ofLeft(error)) 
 } 
 } 
 }
  123. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> { 
 return service.getItems() 
 .map { response -> 
 if (response.isSuccessful) { 
 Response(Either.ofRight(response.body)) 
 } 
 else { 
 val error = /* Pull error out of Response */ 
 Response(Either.ofLeft(error)) 
 } 
 } 
 .onErrorReturn { error -> 
 Response(Either.ofLeft(error)) 
 } 
 } 
 }
  124. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> { 
 return service.getItems() 
 .map { response -> 
 if (response.isSuccessful) { 
 Response(Either.ofRight(response.body)) 
 } 
 else { 
 val error = /* Pull error out of Response */ 
 Response(Either.ofLeft(error)) 
 } 
 } 
 .onErrorReturn { error -> 
 Response(Either.ofLeft(error)) 
 } 
 } 
 }
  125. @Inject 
 class GetItems(val service: ItemService) : UseCase<Response, Request> {

    
 
 override fun execute(request: Request): Observable<Response> { 
 return service.getItems() 
 .map { response -> 
 if (response.isSuccessful) { 
 Response(Either.ofRight(response.body)) 
 } 
 else { 
 val error = /* Pull error out of Response */ 
 Response(Either.ofLeft(error)) 
 } 
 } 
 .onErrorReturn { error -> 
 Response(Either.ofLeft(error)) 
 } 
 } 
 }
  126. @Inject 
 class GetItems( val service: ItemService val db: SqliteDb)

    : UseCase<Response, Request> { 
 
 override fun execute(request: Request): Observable<Response> { 
 return service.getItems() 
 .map { response -> 
 /* Return Left or Right! */
 } 
 .onErrorReturn { error -> 
 Response(Either.ofLeft(error)) 
 } .doOnNext { either -> when (either) { is Either.Left -> { db.saveAll(either.data).subscribe() } } }
 } 
 }
  127. class ItemListViewModel(val getItems: GetItems) { 
 
 fun observeResponse(): Observable<Either<List<Item>>

    { 
 return getItems.execute(GetItems.Request(true)) 
 } 
 
 } 
 

  128. RxDatabase

  129. Observable.create() (or Flowable.create() or unsafeCreate())

  130. Observable.create() (or Flowable.create() or unsafeCreate())

  131. class DbItemDataSource(private val db: SqliteDb) : DbDataSource<Item> { 
 


    override fun saveAll(items: List<Item>): Observable<Boolean> { 
 Observable.fromCallable { 
 items.forEach { 
 db.replaceOrThrow("items", null, items.toQueryString()) 
 } != -1L 
 } 
 } 
 }
  132. RxTesting

  133. 
 @RunWith(RobolectricTestRunner::class.java) 
 class ItemListViewTest { 
 
 private var

    model: ItemListViewModel = /* Instantiate */
 private val myView: ItemListView = /* Create View */ 
 
 private val goodResponse: = 
 Either.Right(/* List of Items */) 
 
 @Test 
 fun testAdapterItems() { 
 Mockito.when(model.fetchItems()) .thenReturn(goodResponse) 
 myView.invokeRefresh() 
 assertEquals( goodResponse.data, myView.getAdapter().items) 
 } 
 }
  134. 
 @RunWith(RobolectricTestRunner::class.java) 
 class ItemListViewTest { 
 
 private var

    model: ItemListViewModel = /* Instantiate */
 private val myView: ItemListView = /* Create View */ 
 
 private val goodResponse: = 
 Either.Right(/* List of Items */) 
 
 @Test 
 fun testAdapterItems() { 
 Mockito.when(model.fetchItems()) .thenReturn(goodResponse) 
 myView.invokeRefresh() 
 assertEquals( goodResponse.data, myView.getAdapter().items) 
 } 
 }
  135. 
 @RunWith(RobolectricTestRunner::class.java) 
 class ItemListViewTest { 
 
 private var

    model: ItemListViewModel = /* Instantiate */
 private val myView: ItemListView = /* Create View */ 
 
 private val goodResponse: = 
 Either.Right(/* List of Items */) 
 
 @Test 
 fun testAdapterItems() { 
 Mockito.when(model.fetchItems()) .thenReturn(goodResponse) 
 myView.invokeRefresh() 
 assertEquals( goodResponse.data, myView.getAdapter().items) 
 } 
 }
  136. 
 @RunWith(RobolectricTestRunner::class.java) 
 class ItemListViewTest { 
 
 private var

    model: ItemListViewModel = /* Instantiate */
 private val myView: ItemListView = /* Create View */ 
 
 private val goodResponse: = 
 Either.Right(/* List of Items */) 
 
 @Test 
 fun testAdapterItems() { 
 Mockito.when(model.fetchItems()) .thenReturn(goodResponse) 
 myView.invokeRefresh() 
 assertEquals( goodResponse.data, myView.getAdapter().items) 
 } 
 }
  137. 
 @RunWith(RobolectricTestRunner::class.java) 
 class ItemListViewTest { 
 
 private var

    model: ItemListViewModel = /* Instantiate */
 private val myView: ItemListView = /* Create View */ 
 
 private val goodResponse: = 
 Either.Right(/* List of Items */) 
 
 @Test 
 fun testAdapterItems() { 
 Mockito.when(model.fetchItems()) .thenReturn(goodResponse) 
 myView.invokeRefresh() 
 assertEquals( goodResponse.data, myView.getAdapter().items) 
 } 
 }
  138. 
 @RunWith(RobolectricTestRunner::class.java) 
 class ItemListViewTest { 
 
 private var

    model: ItemListViewModel = /* Instantiate */
 private val myView: ItemListView = /* Create View */ 
 
 private val goodResponse: = 
 Either.Right(/* List of Items */) 
 
 @Test 
 fun testAdapterItems() { 
 Mockito.when(model.fetchItems()) .thenReturn(goodResponse) 
 myView.invokeRefresh() 
 assertEquals( goodResponse.data, myView.getAdapter().items) 
 } 
 }
  139. 
 @RunWith(RobolectricTestRunner::class.java) 
 class ItemListViewTest { 
 
 private var

    model: ItemListViewModel = /* Instantiate */
 private val myView: ItemListView = /* Create View */ 
 
 private val goodResponse: = Either.Right(/* */) @Before 
 fun setUp() { 
 RxJavaHooks.reset() 
 RxJavaHooks.setOnIOScheduler { Schedulers.immediate() } 
 
 RxJavaHooks.setOnNewThreadScheduler { Schedulers.immediate() } 
 } 
 
 @Test 
 fun testAdapterItems() { 
 /* Test code */
 } 
 }
  140. Architectures? • Redux • MVVM • Cycle.js clone (kevcar.me/mvwtf)

  141. Questions? kevcar.me/rxapplications