“Live long and prosper” — from Presenter to Model

Hi there, my name is Rafał Zieliński. I’m Androd Developer and co-founder of small development studio Mobay Software. I live in the beautiful city of Toruń, Poland. It’s where Nicolaus Copernicus was born.

During my android development career, every time I started writing new app from scratch, there was always that feeling : this time I’ll design it better. Do you know that feeling too ? If yes then this article is for you.

My first app was just simple activity with fragments inside, with all that view logic, business logic, network calls, database methods inside fragments. Well, utils methods were outside in .. utils class :) But that was loooong time ago.

The presenter

Later I read about MVP approach which gives you the logic separated from UI (view) and that was what I was looking for at that time. The code was separated, well organised and easy to test. At least easier to test than before.

Here is simple example of MVP :

class ItemsListContract {
    interface Model: BaseContract.Model {
}
    interface View: BaseContract.View {
fun setItemsView(itemsList: List<Item>)
fun showErrorDialog()
}

interface Presenter: BaseContract.Presenter {
fun loadMoreItemsClicked();
}
}
class ItemsListPresenter(view: ItemsListContract.View,
model: ItemsListContract.Model): ItemsListContract.Presenter {

}
class ItemsListFragment: Fragment(), ItemsListContract.View {

}

The above code defines a contract with three interfaces Model, View, and Presenter. Then there is presenter class that takes view and model instances in constructor and implements Presenter interface, and fragment class that implements View interface. From this example we see that presenter stays between the view and model, which is exactly how MVP works.

There are many examples of MVP implementation and in my apps I used the one above.

What about configuration changes ?

When device is rotated, activity and fragments are destroyed and then recreated again. That means our views are destroyed. The presenter sits between view and model, so when view is destroyed the presenter doesn’t have access to the view anymore. There are two possible ways to handle presenter : either retain it or destroy/recreate it. If we want to retain the presenter we can make it static or use any other global class to store presenter instance.

According to MVP design pattern the presenter should exist as long as view exists and be destroyed/recreated again.

Here are few articles describing the problem :

https://medium.com/@trionkidnapper/android-mvp-keeping-presenters-alive-a91b9e080761

https://hackernoon.com/presenters-are-not-for-persisting-f537a2cc7962

The ideal situation would be to retain the presenter in a more elegant, proper and architecture clean way.

The model

The solution for that problem came exactly on time : ViewModel, a new architecture component from Google.The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way and it retains the configuration changes within it’s scope. A scope can be either fragment or activity, so for example in fragment scope the same instance of ViewModel is retained until fragment is detached. In the case of an activity, when activity is finished.

You know what I want to write next :) Yes, our Presenter can be replaced by ViewModel. Should we do that ? Why not. We have finally a “presenter” that is retained when configuration changes and our data is safe.

Let’s take another architecture component called LiveData, a data holder class that is also lifecycle aware, and which allows to observe data changes. So let’s think : instead of calling view’s methods to drive the UI let the view observe data changes and render UI !

See example of our new presenter below :

class RepoListViewModel(
private var getTopRepositories: GetTopRepositories): BaseViewModel() {

var isLoading: MutableLiveData<Boolean> = MutableLiveData()
var repoList: MutableLiveData<MutableList<RepoEntity>> = MutableLiveData()

private var page: Int = 0
private var perPage: Int = 10

init {
isLoading.value = false
repoList
.value = mutableListOf<RepoEntity>()
}

fun isData(): Boolean {
return repoList.value?.size != 0
}

fun fetchRepoList() {
addDisposable(
getTopRepositories.getTopRepositories(page, perPage)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe {
isLoading
.value = true
}
.subscribe(
{
appendData(it)
isLoading.value = false
page
++
},
{
isLoading
.value = false
}
))
}

private fun appendData(repoListEntity: RepoListEntity) {
var newRepoList = repoList.value
repoListEntity.repoDataItemsList?.forEach {
newRepoList?.add(it)
}
repoList
.value = newRepoList
}

The repoList holds a list of repositories fetched from GitHub and isLoading is simple flag to indicate if progress bar should appear in the view while data is fetched from network. Notice the ViewModel doesn’t hold the reference to view anymore.

Then our view (Fragment) can observe data changes and render UI based on data changes in ViewModel :

private fun observeViewState() {
viewModel?.isLoading?.observe(this, Observer {
repoListRecyclerView
?.setIsLoading(it ?: false)
})
viewModel?.repoList?.observe(this, Observer {
repoListRecyclerView
?.addAll(it)
})
}

When device is rotated, fragment is recreated, the same instance of our RepoListViewModel is received and fragment starts to observe new data changes.

Summary

In this article I tried to describe a new cleaner way to implement MVP design pattern to write better apps, but it’s not the only right architecture that exists. Use whatever you want and feel is right. If my article helped you, write me a comment. If you feel I missed something, write a comment too :)

The code examples are from my demo app available here.

Happy coding !