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.

 

Fragments in ViewPager

Using ViewPager with FragmentPagerAdapter or FragmentStatePagerAdapter appears to be quite easy and enjoyable.

It could be done within few simple steps:

  1. Create layout .xml resource with ViewPager
  2. Create adapter and implement all required methods
  3. Set adapter instance to your ViewPager instance.

Simple? Yes! – but like always only for easiest (also the most common) case

Problem occurs when we want to make something more sophisticated, i.e. add fragments dynamically – provide fragments/pages to adapter from its outside.

The Code

Take a look at quite popular AppIntro library. It gives user a possibility to simply create an app intro just by extending  one AppIntro Activitiy.
One extend, few Fragment slides added in init method, and we got it!

So…the idea of this AppIntro library is to separate and take off weight from a developer to manage all those adapters and viewpagers.

Look in the source code can bring us closer to a basic concept (as I could only imagine it) of this library

Every activity onCreate() callback method calls init(savedInstanceState) method to give a user possibility to add fragments/slies which later are used in FragmentPagerAdapter class.

Caution.

So it looks like all good at the beginning, but yellow light may light up in the head of the developer.

Why?

Creating/providing new fragments instances every time in onCreate() method.

Do you remember what we are doing when we want to create and just add single a fragment to our Activity?

We are checking if this is the first run or recreation after a configuration change.

After orientation change all fragments currently added to FragmentManager are automatically restored and instantiated so there is no need to create them once again.

Same thing is with the ViewPager and FragmentPagerAdapter. Once the adapter adds a fragment to FragmentManager after rotation it will not call getItem(int position) adapter method, but it will look for an already recreated Fragment in FragmentManager.

Line 11 – finding from manager, and only if the fragment is not yet there Line 16 gets new fragment instance from getItem() method

 

Conclusion

We should always remember about the automatic fragment restoration process done via FragmentManager with companion of Activity implementation.

Provide fragments only once at the beginning or only when they are needed (in case of an adapter and getItem(int position) method call) not every time redundantly.