Devices Web DB UI External Interfaces { "id": 11595667, "by": "jamesblonde", "descendants": 0, "score": 2, "time": 1461937655, "title": "Successful way to stop spam email from ResearchGate", "type": "story", "url": "https:\/\/www.researchgate.net\/post" } CREATE TABLE IF NOT EXISTS ItemTable( id TEXT PRIMARY KEY NOT NULL, by TEXT NOT NULL, descendants INTEGER NOT NULL, score INTEGER NOT NULL, time INTEGER NOT NULL, title TEXT NOT NULL, type TEXT NOT NULL, url TEXT NOT NULL )
etc… // OnRefreshListener implementation override fun onRefresh() {/*...*/} fun notifyUpdated() { val items = model.getItems() adapter.items = items setLoadingAnimation(false) } } User Controller View Model
etc… // OnRefreshListener implementation override fun onRefresh() {/*...*/} fun notifyUpdated() { val items = model.getItems() adapter.items = items setLoadingAnimation(false) } } User Controller View Model
etc… // OnRefreshListener implementation override fun onRefresh() {/*...*/} fun notifyUpdated() { val items = model.getItems() adapter.items = items setLoadingAnimation(false) } } User Controller View Model
same responsibilities as before. • View no longer knows about the Model. • Presenter is in full control of what is rendered in View. • Testing is still tough. We need to thoroughly mock IItemListView to unit test.
{ private var model: Model private var loading: Boolean private var items: List<Item> fun onRefresh() { loading = true items = model.getItems() // communicate to View } }
Andre Staltz at JSConf Budapest 2015 • UIs are cycles • UIs are functions • UIs are asynchronous Pull to Refresh List Updates ViewModel: f(refresh) = list updates
Andre Staltz at JSConf Budapest 2015 • UIs are cycles • UIs are functions • UIs are asynchronous Pull to Refresh List Updates ViewModel: f(refresh) = list updates
Andre Staltz at JSConf Budapest 2015 • UIs are cycles • UIs are functions • UIs are asynchronous Pull to Refresh List Updates ViewModel: f(refresh) = list updates
Andre Staltz at JSConf Budapest 2015 • UIs are cycles • UIs are functions • UIs are asynchronous Pull to Refresh List Updates ViewModel: f(refresh) = list updates
Andre Staltz at JSConf Budapest 2015 • UIs are cycles • UIs are functions • UIs are asynchronous Pull to Refresh List Updates ViewModel: f(refresh) = list updates
Staltz at JSConf Budapest 2015 Pull to Refresh List Updates ViewModel: f(refresh) = list updates • UIs are cycles • UIs are functions • UIs are asynchronous Cycle
Andre Staltz at JSConf Budapest 2015 • UIs are cycles • UIs are functions • UIs are asynchronous • UIs are symmetric ViewModel: f(refresh) = list updates
UIs are asynchronous • UIs are symmetric • The user is a function Source: What if the user was a function? by Andre Staltz at JSConf Budapest 2015 ViewModel: f(refresh) = list updates
Observable<Unit>) : Sources class Sinks( val items: Observable<List<Item>>, val loading: Observable<Boolean>) : Sinks } User Reactive Presentation Model Model View
var model: ItemListViewModel private val progressBar //... private val adapter = ItemListViewAdapter() private val subscriptions = CompositeSubscription() private val refreshSubject = PublishSubject.create<Unit>() override fun onAttachedToWindow() { super.onAttachedToWindow() val sinks = model.setUp(Sources(refreshSubject.asObservable())) sinks.loading.subscribe(loadingObserver).addToSubscriptions() sinks.items.subscribe(itemsObserver).addTo(subscriptions) } } User Reactive Presentation Model Model View
backClicks: Observable<Unit>, val shareClicks: Observable<Unit>) : Model.Sources class Sinks( val item: Observable<Item>, val children: Observable<List<Item>>) : Model.Sinks }