Retaining Presenter on configuration change with minimal overhead.

Nikita Kozlov
AndroidPub
Published in
3 min readJun 6, 2016

There are lots of ways to architect an Android application, each with its own pros and cons. Now more and more people start using Model-View-Presenter approach. It makes our code decoupled and lets us test apps better. I’m not going to explain what is it and how to use it, there are lots of good articles about it, you can easily google them. Rather I want to focus on one of the problems it has and try to propose a very simple solution for it.

Retaining presenters on configuration changes.

Let’s imagine that user starts an asynchronous operation and then rotates the device. In this case we might want to notify him about the result, but in order to do so we need to keep reference to this operation. And since presenter is responsible for handling such operations, retaining him on configuration change sounds like a good idea.

In ideal world we want Android framework to do all the job for us. It is already taking care of managing lifecycle for activities and fragments, so it would be very nice of him to take care of presenters as well. Unfortunately it doesn’t. But it provides all we need to make implementation looks like a bunch of new hook methods.

Android can already preserve Loaders and Fragments on configuration changes. It uses onRetainNonConfigurationInstance() method, to return an instance of NonConfigurationInstances class to ActivityThread so later on new Activity object will receive it in attach(). This class is package private and defined separately in Activity and FragmentActivity. Let’s take a look into NonConfigurationInstances class from FragmentActivity, since AppCompatActivity based on it:

static final class NonConfigurationInstances {
Object custom;
List<Fragment> fragments;
SimpleArrayMap<String, LoaderManager> loaders;
}

As we can see this class holds references to retained Fragments and all LoaderManagers. This is how they survive rotation. But most interesting part is field custom, it can help us solve our issue. To set it we just need to override method onRetainCustomNonConfigurationInstance().

The simpler the better.

To solve our problem we need a manager that will store presenters and generate unique ids that can be stored in a Bundle. Those ids will allow our Fragments to restore their presenters after configuration change.

Presenter creation and lifecycle could be managed by Fragments and Activities, since no one knows better what is going on with them then they do. Lets create base classes that will hide all this implementation.

This leads us to a very simple and concise interface. For Activities and Fragments it is the same:

public class PresenterFragment<P extends Presenter, V extends View> extends Fragment {    protected P getPresenter() {}
protected void onPresenterRestored() {}
protected P onCreatePresenter() {}
protected V getPresenterView() {}
protected boolean retainPresenter() { return true; }
}

For Presenter:

public interface Presenter {    void onAttachView(View view);
void onDetachView();
void onDestroy();
}

As you can see PresenterFragment got a few new hook methods, but we need to override only two of them onCreatePresenter() and getPresenterView(). Every thing else will be managed by base class.

And that is it. Presenter will survive configuration change. After restoration PresenterFragment#onPresenterRestored() or PresenterActivity#onPresenterRestored() will be called in fragment or activity respectively. If we navigate to new screen either fragment or activity, old screen’s presenter will be destoroyed and Presenter#onDestroy() method will be called, so we can stop ongoing operation, or unsubscribe from result in case of RxJava.

A few words about lifecycle.

In this approach I decided that Presenter should be attached in onStart() and be detached onStop(), because usually we don’t need it before. But, please, pay attention that Presenters are restored during Activity#onCreate(), so in PresenterFragment#onPresenterRestored() it is possible that fragment’s activity is still in the process of being created.

Conclusion.

As a result we got a very concise solution that is very easy to work with. To make it even simpler I made a library, please, check my github repo for more information. There you can find an example as well. Demo covers most of the cases including navigation with fragments, nested fragments and ViewPager.

I would like to hear your opinion about this solution. If you have any suggestions please feel free to rise an issue on GitHub.

--

--