Skip to content

Advanced Concepts

Gabriel Peal edited this page Jul 24, 2018 · 22 revisions

MvRxViewModel

Subscribing to state manually.

There may be times in which you want to subscribe to state changes outside of it simply calling invalidate() on your view. From within your viewModel, you can simply call subscribe { ... } From outside, you must pass in a LifecycleOwner. The Airbnb MvRxFragment adds this extension which makes subscribe automatically pass itself in.

Subscribing to current + previous state

If you need the previous version of the state in addition to the new state, you can use subscribeWithHistory instead of subscribe.

Subscribing to only certain state updates

MvViewModel subscriptions have an optional shouldUpdate parameter. It is a lambda that takes the old state and new state and returns whether to call the subscriber. This is functionally equivalent to having an if block in the beginning of your subscriber.

MvRx comes with a few shouldUpdate helpers out of the box including:

  • onSuccess: Calls the subscriber when an Async state property transitions from non-Success to Success.
  • propertyWhitelist: A vararg of state properties to monitor for updates.

Pagination

A successful pattern for pagination has been to have one state property store Async<List<T>> while another stores List<T>. The Async property contains the network request of the current page. This can be checked to prevent us from requesting duplicate pages simultaneously and can be queried to determine whether or not to show a loading indicator. The reducer for the pagination request should append results to the results list if it is successful like:

MvRxReviewsRequest.create(1234, offset).execute {
    copy(reviews = reviews.appendAt(it()?.reviews, offset), reviewRequest = it)
}

MvRx also includes appendAt to replace everything after the specified offset with the results. It handles edge cases like ignoring appending null and handling index out of bounds issues.

Dependent Requests

If you have an async request that is dependent on another, execute them like this:

/* In ViewModel */
init {
    onSubscribe(onSuccess(MyState::request1)) {
        fetchRequest2()
    }
}

MvRxView