Skip to content

Part1.1

Arnaud Giuliani edited this page Sep 27, 2018 · 60 revisions

Steps


1.1 - First ViewModel & LiveData with Weather Detail View

This view simply displays weather detail chosen from weather view. Let's start our new ViewModel class from the DetailPresenter class (package view/detail).

TL;DR πŸš€

Create the DetailViewModel class from the DetailPresenter class. Write the getDetail() function to push states with LiveData (as Loading,DetailLoaded and Failed states). Update the DetailActivity to use the ViewModel instead of Presenter.


TODO 🎯 - DetailViewModel

Let's create our ViewModel class:

  • Create class DetailViewModel in detail package and make it inherits from RxViewModel

We won't use any constructor injection for now, as the default ViewModel API doesn't allow us to do so (In next exercises, we will use Koin).

  • Write the following properties:
class DetailViewModel : RxViewModel() {

	/*
	 * Dependencies out of constructor. Will be filled later by DetailActivity
	 */
	lateinit var dailyForecastRepository: DailyForecastRepository
	lateinit var schedulerProvider: SchedulerProvider
  • Write a data class to represent our view state, at the end of DetailViewModel class:
data class DetailLoaded(val weather: DailyForecast) : ViewModelState()
  • Add LiveData property called states (backed by private MutableLiveData):
private val _states = MutableLiveData<ViewModelState>()
val states: LiveData<ViewModelState>
    get() = _states
  • Copy the getDetail() function from DetailPresenter and use the states property to write Detail,Loading and Failed instead of calling MVP View.
_states.value = Loading
_states.value = DetailLoaded(...)
_states.value = Failed(...)

Warning ⚠️: LiveData property can be updated with value or postValue. This last is used when app is in background.


TODO 🎯 - Update Koin configuration

Android Architecture ViewModel API is used here without any dependency injection support for this exercise. In app_module.kt, just delete the presenter declaration from Koin:

// Delete this
factory<DetailContract.Presenter> { DetailPresenter(get(), get()) }

TODO 🎯 - DetailActivity

We need to declare our ViewModel in DetailActivity.kt in order to use the getDetail() function and listen to ViewModel states.

  • Remove overrides from DetailContract
  • Remove onStart(), onStop() functions and presenter property

Now prepare your DetailViewModel:

  • In onCreate() function, declare the DetailViewModel ViewModel with ViewModelProviders:
val detailViewModel = ViewModelProviders.of(this).get(DetailViewModel::class.java)
  • Then get dependencies for DetailViewModel with Koin:
// Apply dependencies "manually"
detailViewModel.apply {
       // import org.koin.android.ext.android.get to use the get() function, to retrieve dependencies from an Activity
       dailyForecastRepository = get()
       schedulerProvider = get()
    }
  • And now let's observe our detailViewModel for incoming states. We use the Kotlin When pattern matching to bind Failed and Detail:
detailViewModel.states.observe(this, Observer { state ->
	when (state) {
        is Failed -> showError(state.error)
	    is DetailViewModel.DetailLoaded -> showDetail(state.weather)
	}
})
  • Finally, call the getDetail() function from detailViewModel, with detailId property

Warning ⚠️: not all states are necessarily bound, it depends on our usage. The view decide to bind what it needs from the given ViewModel contract (the inner State or Event of ViewModel)


Test & Run it πŸ‘

Check that the app is OK on your device (you can select a weather detail).

For unit test:


Clone this wiki locally