### Android Unidirectional Data Flow with LiveData #### Improving Coinverse’s Performance and Structure **The** _Unidirectional Data Flow_ (UDF) pattern has improved the usability and performance of [**Coinverse**](https://play.google.com/store/apps/details?id=app.coinverse) since the first beta launched in February. Coinverse is the first app creating audiocasts covering technology and news in cryptocurrency. Upgrades using UDF include more efficient newsfeed creation, removal of adjacent native ads, and faster audiocast loading. The UDF pattern organizes the app into three main areas, view **state, events**, and **effects** ensuring the app is modularized and reliable. I learned of the UDF pattern from episode 148 of the [Fragmented podcast](https://fragmentedpodcast.com), [_Evolving Android architectures (Part 1)_](https://fragmentedpodcast.com/episodes/148/) with [Kaushik Gopal](https://medium.com/u/b85c7e530b1f) at [Instacart](https://medium.com/u/45aee787ef17) and [Donn Felker](https://medium.com/u/e75f3da9f41a). On first listen it was interesting, but a large overhaul. UDF became compelling as I worked on fixing bugs and realized how complex various flows had become. The examples of UDF I’ve seen thus far have been with [Rx](http://reactivex.io/). Rx a powerful and customizable tool for creating streams of data that can be observed in real-time. However, [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) provides the same benefit of observing state changes and on top of that is simple, directly integrates with Android’s [architecture components](https://developer.android.com/topic/libraries/architecture), and handles Android’s lifecycle events by default. If unfamiliar, check out Google’s [Jose Alcérreca](https://medium.com/u/e0a4c9469bb5)’s [talk on LiveData](https://www.youtube.com/watch?v=2rO4r-JOQtA). To try out UDF I refactored the newsfeed flows in Coinverse as we’ll walkthrough below. <a href="https://medium.com/media/8b9dd6f492bd3f25f79f7bf5cbe0388e/href">https://medium.com/media/8b9dd6f492bd3f25f79f7bf5cbe0388e/href</a> ### UDF Background UDF pattern, a.k.a. _Unidirectional Data_ or _State Flow_ was originally popularized in web development with Facebook’s [React](https://reactjs.org) and [Readux](https://redux.js.org) state management, and [Flux](https://facebook.github.io/flux/) UI libraries. Early Android [experimentation](https://www.youtube.com/watch?v=SsH_rByBbq4) can be found from [Brian Egan](https://medium.com/u/e363db1ba716) and [Guillaume Lung](https://medium.com/u/d85794e20ff7) at [SoundCloud](https://medium.com/u/94f5b1677695) in 2015. [Jake Wharton](https://medium.com/u/8ddd94878165)’s talks on Rx educated developers on [reactive programming](https://en.wikipedia.org/wiki/Reactive_programming) which are fundamental to UDF. #### Growing Number of Android Apps Adopting To name a few… * [Kaushik Gopal](https://medium.com/u/b85c7e530b1f) and [Laimonas Turauskas](https://medium.com/u/eeb6311ddecd) @ [Instacart](https://medium.com/u/45aee787ef17) * [Dan Hill](https://medium.com/u/630ba9fc9922) @ Robinhood * [Donald Chen](https://medium.com/u/a03444eaea8f) @ [Instagram Engineering](https://medium.com/u/a4c6efa67fe0) / Lyft * [Cesar Valiente](https://medium.com/u/8317e8033cb6) @ Microsoft  App companies adopting UDF ### Model View View Model — MVVM  Gem Lake, Yosemite Emigrant Wilderness Trail For the first iteration of Coinverse I used the _Model View View Model_ (MVVM) approach. MVVM separates the UI from the business logic, improving readability and organization. However, as an app grows with MVVM it becomes a lake of data. Information flows in, out, and around at many points via _Activities_ and _Fragments_ with _Data Binding,_ _ViewModels_, and _Repositories_. This adds complexity for keeping track of logic, debugging, and testing, which requires mocking many components. ### UDF Advantages  pc — [Ned Scher](https://www.linkedin.com/in/ned-scher-60bbb152/), Waterfall at Yosemite National Park UDF is a waterfall, information flows in one direction through a single source providing many benefits. * One point of entry for streams — The UI and business logic interact through single points of entry. * Control UI involving async events — Know exactly when and where things begin and finish * Debug issues — Easy to follow sequence of events and identify errors * Streamlined tests — The majority of logic is contained in the ViewModel requiring less mocking. ### LiveData LiveData provides a straightforward approach to implementing UDF. * Lifecycle aware * Can emit multiple or single events * Concise code * Quick to implement <a href="https://medium.com/media/aece5d95a459fab51fe4afcff559f91b/href">https://medium.com/media/aece5d95a459fab51fe4afcff559f91b/href</a> ### View State, Events, and Effects #### ViewState  Coinverse’s main newsfeed View **state** is responsible for holding the final view’s persisted data. This entails all of the content shown to a user on a screen, including information about the content such as enabled statuses. Looking at Coinverse’s main newsfeed above, examples of view **state** include the contents of the toolbar, what timeframe and the feedtype of feed to display, as well as the contentList to populate the feed with. #### Events  **ContentSelected(…)** View **events** consist of both user interface and system initiated actions. UI actions include button presses and text input, whereas system actions might be Android lifecycle events and screen rotation. In the case of _The Coinbase Blog’s_ content selected above a view **event** is created, ContentSelected. The **event** will share information with the business layer to initiate the retrieval of the audiocast selected. #### Effects  **ContentSwiped(…)** View **effects** are one time UI occurrences that don’t persist. **Effects** include navigation, dialogs, and toasts. **Effects** are created by the business layer to initiate changes in the UI. When the _CCN_ item above is swiped right, the business layer adds a _saved_ label to the content. The business layer sends an **effect**, ContentSwiped**,** informing the UI of the change in the content’s label. The UI can then remove the content from the main newsfeed. ### App Structure  Let’s understand how the one-way flow of data is structured. The _View_ handles all UI and system level actions stored in a single stream. The stream is sent to the _ViewModel_ that receives the actions and handles them accordingly in the business logic. The _ViewModel_ is the source of truth for the view **state** and creates any necessary **effects**. The _ViewModel_ also handles requests to the data _Repository_ layer, managing the results **loading**, success (**content**), and **error** states returned from the _Repository_ with an Lce object (more on Lce's below). Both the **state** and **effects** are observed by the _View,_ updating any changes from the _ViewModel_ in real-time. ### Implementation  mainfeed loading We’ll use Coinverse’s main newsfeed loading as our example for how to implement UDF. #### Step 1 of 6 — Define Models <a href="https://medium.com/media/e3e457ec723be5f770f4c050214571d0/href">https://medium.com/media/e3e457ec723be5f770f4c050214571d0/href</a> * View **state —** Stored as a LiveData object in the _ViewModel,_ storing the contentList of LiveData type * View **event** and **effect** — Use Kotlin’s [Sealed class](https://kotlinlang.org/docs/reference/sealed-classes.html) to pass one time events The view **state** uses LiveData because it’s important the data is immutable vs. MutableLiveData. Otherwise, the flow of data would not be unidirectional, and the state could be changed in many places. View **events** and **effects** are not persisted in the _ViewModel_. A Sealed class, like an Enum, but on a class level, is used to pass information. Sealed classes define a parent and child class with or without data. TheScreenLoad **event** is a data class with data about what the _ViewModel_ should load. Whereas the UpdateAds **effect** is a class without data telling the view to update the ads in the newsfeed. #### Step 2 of 6 — Pass events to ViewModel <a href="https://medium.com/media/21b7345af796983c640793c3fbfdf7ee/href">https://medium.com/media/21b7345af796983c640793c3fbfdf7ee/href</a> In this example, when the system action of onCreate occurs, a ScreenLoad event is added to the stream of view events and sent from the _Fragment_ to the _ViewModel_ to start creating the main feed. All of the events created in the _View_ / _Fragment_ are added to a _LiveData_ object \_viewEvent, a MutableLiveData object which updates the immutable LiveData object. I’m using the pattern of passing all of the events in onResume based on [Kaushik](https://medium.com/u/b85c7e530b1f)’s [sample](https://github.com/kaushikgopal/movies-usf). The LiveData stores data wrapped in an Event. As explained by [Jose](https://medium.com/u/e0a4c9469bb5) in his [LiveData post about events](https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150), events ensure a single unique object is added to a stream. This avoids the accidental creation of multiple objects for a single action. #### Step 3 of 6 — Process events  mainfeed loaded <a href="https://medium.com/media/1e82719128462cbbc400fb2ceab73db4/href">https://medium.com/media/1e82719128462cbbc400fb2ceab73db4/href</a> The _ViewModel_ receives incoming events, handling each event in a when statement based on the type of **Sealed** ViewEvent class. For ScreenLoad, the entireViewState is updated with the required data. To populate the newsfeed a request to the _Repository_ with getMainFeed is made. **Update State Value** In cases where an attribute of the ViewState needs to be updated rather than the entire ViewState, Kotlin’s shallow [_copy_](https://kotlinlang.org/docs/reference/data-classes.html#copying) function is useful. <a href="https://medium.com/media/ce1bf00297c228e57a7216047f915529/href">https://medium.com/media/ce1bf00297c228e57a7216047f915529/href</a> #### Step 4 of 6 — Manage Network Requests with LCE Pattern <a href="https://medium.com/media/abb3971ab92689aa13784def4501b3e3/href">https://medium.com/media/abb3971ab92689aa13784def4501b3e3/href</a> To manage network requests, [Kaushik](https://medium.com/u/b85c7e530b1f) introduces the Lce **Sealed** class object with three states, **loading**, **content**, and **error**. The **content** state represents a successful request. <a href="https://medium.com/media/115cf44f615dca588145ff82c08df8f1/href">https://medium.com/media/115cf44f615dca588145ff82c08df8f1/href</a> A **Sealed** class is also useful for returning different types of results. <a href="https://medium.com/media/0282a893889f04b825cc9f73d6a231fb/href">https://medium.com/media/0282a893889f04b825cc9f73d6a231fb/href</a> getMainFeed’s network request shares send the Lce states to the _ViewModel_ via the LiveData stream. The PagedListResult class can be passed into the Lce for both the **content** and **error** states. The _ViewModel_ will then manage each state appropriately. #### Step 5 of 6 — Handle LCE States  mainfeed error The gif shows something has gone awry. We’ll see how the error is handled in the _ViewModel_. <a href="https://medium.com/media/2e31d1bd3a6304c6a19b4728f9102597/href">https://medium.com/media/2e31d1bd3a6304c6a19b4728f9102597/href</a> UDF has streamlined both methods of requesting new content from the network and retrieving the updated content from the [Room](https://developer.android.com/topic/libraries/architecture/room) database. Prior to using UDF, Coinverse called two repository methods separately to populate the main newsfeed. When the feed is loading the existing Room database content is returned so that the user is not staring at an empty screen. For the successful Content case, the updated content from Room is returned. For errors requesting new content, the existing Room content is also displayed similar to theLoading case. In the error above, a SnackBar view **effect** is passed to the _Fragment_ to display the error message. The _ViewModel_ observes each Lce state with a LiveData SwitchMap. The SwitchMap passes in one LiveData object and returns a new and different LiveData object that is saved to the view **state**. Like all LiveData, a SwitchMap must be observed in the view in order for the value to be emitted within the map inside the _ViewModel_. #### Step 6 of 6 — Observe State Change! <a href="https://medium.com/media/503f19392a8e77dba776d7ab367549a1/href">https://medium.com/media/503f19392a8e77dba776d7ab367549a1/href</a> Now the view **state** may be observed when an update occurs. The view **effects** are observed in the same way. ### Bonus — Removing Adjacent Ads  auto adjacent ads detection In addition to a streamlined newsfeed above, UDF has improved how Twitter’s native [MoPub](https://www.mopub.com) ads are shown in the newsfeed. MoPub’s MoPubRecyclerAdapter does not have a built-in approach to avoid adjacent ads from showing. Content can be swiped to be saved or dismissed, eventually causing two ads to appear next to each other. Prior to UDF, this was handled with a manual swipe-to-refresh by the user. With UDF there is a contentLabeled view **state**. When the status of the view **state** changes, meaning an item is labeled to be removed from the main feed, a check for adjacent ads is made. If removing the content creates adjacent ads, the ads are automatically refreshed. ### Trade-Offs Using LiveData for the Unidirectional Data Flow has been great, but it’s not perfect. LiveData is only applicable for logic impacting the UI. For non-UI logic LiveData will not be observed since it requires lifecycle to be passed in. For these instances, [Kotlin coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) or Rx may be used. If no UI is involved then an even better solution might be to offload the logic completely to the backend with [Firebase Cloud Functions](https://firebase.google.com/docs/functions/callable#call_the_function). There’s not as much customization with LiveData for things like threading. With this year’s latest Google I/O updates coroutines appear to easily integrate with LiveData offering more customization. ### Coinverse Next Steps * **Unidirectional Data Flow —** Expanding to the rest of Coinverse’s app * **JUnit testing** — Now that the majority of the newsfeed logic is modularized in the _ViewModel_, JUnit testing will be easier with less mocking of components. * **Kotlin coroutines —** Exploring integration with LiveData #### Resources * Slides — [Unidirectional Data Flow por Adam Hurwitz](https://docs.google.com/presentation/d/1bj-lG2ghJO5EVIJRrCt3eH-lZsz8ChPc1hVXZ_KYpD8?rm=minimal) @ [Medellín Android MeetUp](https://www.meetup.com/Medellin-Android/) * Notes — [Unidirectional Data Flow guide](https://docs.google.com/document/d/13fmrGJbGHNEPo3FN7IDmwQjxjXK3qoACSRqjyawV32k?rm=minimal) #### I’d love your feedback on the [Coinverse](https://play.google.com/store/apps/details?id=app.coinverse) beta! [_Follow me_](https://medium.com/@AdamHurwitz) to be updated on a Unidirectional Data Flow sample app and more. A **big thanks** to [Cristián Gomez](https://twitter.com/Iyubinest) and [Carlos Daniel](https://medium.com/u/eaf44c102d99) of the [Medellín Android MeetUp](https://www.meetup.com/Medellin-Android/) for organizing the talk! If you are in Medellín I recommend stopping by their MeetUp.  [Medellín Android talk — Unidirectional Data Flow por Adam Hurwitz](https://www.youtube.com/watch?v=Elp-Z-pQTpM) 