Lakshman Chilukuri Lakshman Chilukuri - 4 months ago 95
Android Question

Android MVP Strategy

I am migrating my apps to MVP. Have taken hints on a static presenter pattern from this konmik

This is my brief MVP strategy. Removed most of the boilerplate and MVP listeners for brevity. This strategy has helped me orientation change proof my background processes. The activity correctly recovers from a normal pause compared to pause which is finishing the activity. Also the Presenter only has application context so it does not hold onto activity context.

I am not a java expert and this is my first foray into MVP and using a static presenter has made me uncomfortable. Am I missing something? My app is working fine and has become much more responsive.

View

public class MainActivity extends Activity{
private static Presenter presenter;

protected void onResume() {
if (presenter == null)
presenter = new Presenter(this.getApplicationContext());
presenter.onSetView(this);
presenter.onResume();
}

protected void onPause() {
presenter.onSetView(null);
if(isFinishing())presenter.onPause();
}
}


Presenter

public class Presenter {
private MainActivity view;
Context context;
public Model model;

public Presenter(Context context) {
this.context = context;
model = new Model(context);
}

public void onSetView(MainActivity view) {
this.view = view;
}

public void onResume(){
model.resume();
}
public void onPause(){
model.pause();
}

}


Model

public class Model {

public Model(Context context){
this.context = context;
}
public void resume(){
//start data acquisition HandlerThreads
}
public void pause(){
//stop HandlerThreads
}

}

Answer

I would suggest two things.

  1. Make Model, View, and Presenter into interfaces.
    • Your MVP-View (an Activity, Fragment, or View) should be so simple it does not need to be tested.
    • Your MVP-Presenter never directly interacts with the Activity/Fragment/View so it can be tested with JUnit. If you have dependencies on the Android Framework is bad for testing because you need to Mock out Android objects, use emulator, or use a Testing Framework like Roboelectric that can be really slow.

As an example of the interfaces:

interface MVPView {
    void setText(String str);
}

interface MVPPresenter {
    void onButtonClicked();
    void onBind(MVPView view);
    void onUnbind();
}

The MVPPresenter class now does not depend on the Android Framework:

class MyPresenter implements MVPPresenter{
    MVPView view;

    @Override void bind(MVPView view){ this.view = view; }
    @Override void unbind() {this.view = null; }
    @Override void onButtonClicked(){
        view.setText("Button is Clicked!");
    }
}
  1. Instead of making the Presenter a static class, I would make it a Retained Fragment. Static objects need to be tracked carefully and removed for GC manually whenever they are not needed (otherwise it's considered a memory leak). By using a retain fragment, it is much easier to control the lifetime of the presenter. When the fragment that owns the retain fragment finishes, the retain fragment is also destroyed and the memory can be GC'd. See here for an example.