title: Updating Immutable View State Values in Android Unidirectional Data Flow
body: <h1>Question</h1>
  
  <p><strong>I'm looking to refactor an immutable view state's values in the Android ViewModel (VM) in order to do the following:</strong> </p>
  
  <ol>
  <li><strong>Update the view state in the VM cleanly without copying the entire view state</strong></li>
  <li><strong>Keep the view state data immutable to the view observing updates</strong></li>
  </ol>
  
  <p>I've built an Android Unidirectional Data Flow (UDF) pattern using LiveData to update the view state changes in the VM that are observed in the view.</p>
  
  <p>See: <a href="https://proandroiddev.com/udf2-0-5052c3e1c62a" rel="nofollow noreferrer"><em>Android Unidirectional Data Flow with LiveData — 2.0</em></a></p>
  
  <p>Full sample code: <a href="https://github.com/AdamSHurwitz/Coinverse" rel="nofollow noreferrer"><em>Coinverse Open App</em></a></p>
  
  <h1>Implementation</h1>
  
  <p>The existing implementation uses nested LiveData. </p>
  
  <ul>
  <li>One LiveData <code>val</code> to store the view state in the VM </li>
  <li>Nested LiveData for the view state attributes as immutable <code>val</code>s</li>
  </ul>
  
  <pre><code>// Stored as viewState LiveData val in VM
  data class FeedViewState(
      val contentList: LiveData&lt;PagedList&lt;Content&gt;&gt;
      val anotherAttribute: LiveData&lt;Int&gt;)
  </code></pre>
  
  <p>The view state is created in the VM's <code>init{...}</code>. </p>
  
  <p>Then, in order to update the view state it must be copied and updated with the given attribute because it is an immutable <code>val</code>. If the attribute were to be mutable, it could be reassigned cleanly without the <code>copy</code> in the VM. However, being immutable is important to make sure the view cannot unintentionally change the <code>val</code>.</p>
  
  <pre><code>class ViewModel: ViewModel() {
      val viewState: LiveData&lt;FeedViewState&gt; get() = _viewState
      private val _viewState = MutableLiveData&lt;FeedViewState&gt;()
  
      init {
          _viewState.value = FeedViewState(
             contentList = getContentList(...)
             anotherAttribute = ...)
      }
  
      override fun swipeToRefresh(event: SwipeToRefresh) {
          _viewState.value = _viewState.value?.copy(contentList = getContentList(...))
      }
  }
  </code></pre>