Presenter Abstraction Layer in Open Event Organizer Android App
Open Event Organizer App design follows Model View Presenter (MVP) architecture which enables heavy unit testing. MVP is a trending architecture design followed these days. If you are not aware of MVP architecture, then please refer any of the tutorial (few links are given at the end of this blog) about it before reading this. In the design, the code becomes little repetitive as the application size increases due to so many presenters and views, which degrades the code readability. So to avoid this and keep the functionality code clean in the App, we have created a Presenter Abstraction Layer which contains the repetitive code and the layer is extended wherever required in the app. I will be talking about the Presenter Abstraction Layer implementation through the App in this blog.
First of all, create a base interface. The base interface contains methods which every presenter will have. The base interface for presenter in the App looks like:
public interface IBasePresenter { void start(); void detach(); }
In the method start, presenter loads all the required data from the model and sends it to the view. And releases all the resources in detach. These two methods are required in all the presenters. This interface is extended by other two interfaces which will be actually used by the views. The relevant code is:
public interface IPresenter<V> extends IBasePresenter { void attach(V view); } public interface IDetailPresenter<K, V> extends IBasePresenter { void attach(K key, V view); }
Method attach is used to attach view and the data id (if required) to the presenter. In the app, most of the presenters require an extra data which is used in loading data from the model. Hence two interfaces are extended from the base interface. Now comes the implementation part.
public abstract class BasePresenter<V> implements IPresenter<V> { private V view; private CompositeDisposable compositeDisposable; @Override @CallSuper public void attach(V view) { this.view = view; this.compositeDisposable = new CompositeDisposable(); } @Override @CallSuper public void detach() { view = null; compositeDisposable.dispose(); } protected V getView() { return view; } protected CompositeDisposable getDisposable() { return compositeDisposable; } }
The App uses ReactiveX Observables for async operations which contain fragment/activity context hence these need to be disposed at some lifecycle of fragment/activity. detach nulls the view and disposes the compositeDisposable. This method is called at the onStop lifecycle of fragment/activity. The observable subscriptions are one of the major reasons for memory leaks if not disposed at correct lifecycle in Android. So the detach method is called at onStop lifecycle when activity goes into background or fragment is switched by FragmentTransaction. Another base presenter class looks like:
public abstract class BaseDetailPresenter<K, V> extends BasePresenter<V> implements IDetailPresenter<K, V> { private K id; @Override @CallSuper public void attach(K id, V view) { super.attach(view); this.id = id; } protected K getId() { return id; } }
This class extends the previous one except for the attach method. As the presenters extending this, require an extra data id which is passed through this method. So the id can be used in the presenter extending this class using getId. The presenters in the app extend one of these two classes. This helps in making a firm app structure and the development process easier. Abstraction layer should be used wherever same code is repeated. This increases code readability and decreases the chances of creating bugs especially when a team is working on the same project.
Links:
1. MVP for Android: how to organize the presentation layer, by Antonio Leiva
2. Android Code That Scales, With MVP, by Nathan Barraille
3. Ted Mosby – Software Architect, by Hannes Dorfmann