MVP for Android

Have you ever had problems with the lifecycle of an Activity or Fragment? The necessity to handle things like a configuration change, an activity kill because of low memory issues, removal of the entire app process, etc. always distinguished Android mobile enviroment from other application runtime enviroments.
In our Android world there are many platform specific factors that we should pay attention to while writing every single line of code and especially during a development of libraries/frameworks.

The same is the case when we want to use any architectural pattern…

For a long time I was looking at the Model View Presenter topic for an Android with some distance. Not MVP just as a pattern, because it’s clear that every responsibility separation is great, but primaily its implementation in an Android way.

Assumptions

I begin my analysis of the Presenter part of MVP model by adopting following assumptions:

  • We will use Presenters in our system components (Activities or Fragments)
  • Presenters should live in the memory only as long as the components they belongs to:
    • The Presenter should be retained on configuration changes – i.e. if we want to retain long running tasks (even if an activity is being recreated in the same moment)
    • The Presenter should be destroyed if a related component like activity or fragment is destroyed, either because of memory running out problem or just because of user action – we don’t want to needlessly waste memory and store presenter in memory if related activity/fragment is currently not there
    • The Presenter should be recreated after process recreation (if proces of our app was killed because of low memory issues) – we must ensure reliabilty and possibility to restore presenter state later even if proces is destroyed
  • A presenter implementation should impact on the other components code in the least possible way

Possible options

Having those assumptions we could think of our proper MVP implementation. First conspicuous and most problematic thing is proper presenter preservation in combination with the Activity/Fragment lifecycle.

I collected possible implementations solving this problem and I will describe them briefly:

  1. Save the Presenter state in a Bundle
    The first implementation on this list which makes any sense. Use onSaveInstance bundle to save the Presenter state and later recreate it.

    Pros:

    • Pretty simple
    • We could save and recreate the presenter state in the bundle object (on configuration changes or process recreation)

    Cons

    • We could not retain long running tasks because on the activity recreation our task will be restarted (or will leak activity/fragment if we not kill or detach it from our component)
  2. Use a Fragment with setRetainInstance

    Presenter could be stored inside the Fragment with a flag setRetainInstance set to true.

    Pros:

    • We could save and recreate the presenter state in a Bundle object
    • We could retain long running tasks because they retain the configuration change same as the retained Fragment

    Cons:

    • We could not use this option if we want to implement an Activity only solution
    • setRetainInstance Fragment could not be
      • used as a child fragment
      • used properly on the back stack
    • setReitanInstance Fragment should not contain any references to views because of potential (view/context/activity) memory leak issues
  3. Retain a presenter using Activity onRetainCustomNonConfigurationInstance method

    We could store presenter references inside an object retained via onRetainCustomNonConfigurationInstance method

    Pros:

    • The Presenter state retained between config changes
    • We could retain long running tasks

    Cons:

    • The method available only for activities, could not be used with fragments
  4. Hold presenter in some static singleton

    Simply store the presenter reference inside some static storage, i.e. a map of presenters

    Pros:

    • We could save and recreate the presenter state in a Bundle object
    • We could retain long running tasks because they live as long as application process

    Cons:

    • Presenters should live in a memory only as long as its component (Activity/Fragment) is in memory. Using a static map we are changing the scope of responsibility.
      There is a possibility that activity will be removed from memory because app needs its in other place, but the presenter for that activity will still be in the memory held by some static references. This is an unnecessary waste of the memory.
    • Static fields are bad
  5. New method!
    Save and retain a presenter inside the Loader object
    We could use the Loader retaining mechanism to store our Presenter. This method works universally both for activities and fragments.

    Pros:

    • The Presenter retained between config changes
    • We could retain long running tasks
    • We could recreate a presenter even if the whole proces will be recreated
    • An independent usage in an Activity or Fragment.

    Cons:

    • Loaders are not so popular – but using my helper library for this make this problem negligible

Summary

You can see that there are a lot of methods to deal with Presenter retain. To make comparision easier to visualise I created a table with all presented options:

Android MVP - Presenter retain comparision

We could easily notice that last implementation using Loader to retain meets all of our assumptions from the beginning and looks like the best choice (and as you will see later – also easy) to implement.

Originally this ‘Loader’ idea is not mine. It was suggested by Ian Lake (Google Dev) as an answer to my question in one of Google ‘Developer Show’ series video:

We’ve got the winner

Now you can scratch your head and ask ‘Loader? I don’t know what it is?’.

I’m aware that many people don’t use or don’t know loaders because at first glance they may look strange and there are some issues with them in specific situations.

In response to the following reaction I created library called Tomorrow!

logo

To help all of you in MVP pattern with loaders (to retain presenters) implementation without even knowing or having any idea how loaders really work.
Tomorrow MVP library and its full description/documentation is available on GitHub and also as a dependency on maven server.

 

Michał Łuszczuk

Lead Android developer @Blix-Qpony Group