Example of Model View Presenter pattern on Android

There’re many interesting descriptions about the Model View Presenter (MVC) pattern and its ins and outs, for example this (at the end of the article).

It’s a recommended pattern to make views independent and take most of logic out from your activities.

This post shows an extremely brief example about implementing MVP on Android.

MVP flow

Initial settings

The goal is simple, to update a progress indicator. To achieve it, you will use a couple of external libraries:

So, the build gradle file:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.0"

    defaultConfig {
        applicationId "com.example.danilao.rxtest"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    lintOptions {
        disable 'InvalidPackage'
        abortOnError false
    }

    packagingOptions {
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.0.0'

    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'com.github.lzyzsd:circleprogress:1.1.0@aar'
}

The view

The unique interaction will be through a button. When you click it, the progress indicator will be updated:

public interface MainView {
    void updateProgress(int progress);
}

The presenter

The presenter has to complete the complex operations related to guess the new progress value and communicate the result to the view:

public interface MainPresenter {
    void calculateProgress(int currentProgress);
}

It uses the current value to calculate the next one. However, in this example you’ll work with a silly implementation:

public class MainPresenterImpl implements MainPresenter {

    private MainView mainView;

    public MainPresenterImpl(MainView mainView) {
        this.mainView = mainView;
    }

    @Override
    public void calculateProgress(int currentProgress) {
        int finalValue = new Random().nextInt(100);
        mainView.updateProgress(finalValue);
    }
}

For simplicity, in this example we’re not defining a model.

Final step

Finally, all connections are made into the Activity class:

public class MainActivity extends AppCompatActivity implements MainView {

    @Bind(R.id.donut_progress) DonutProgress donut;
    @Bind(R.id.button) Button button;

    MainPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        updateProgress(0);

        presenter = new MainPresenterImpl(this);
    }

    @OnClick(R.id.button)
    public void start() {
        presenter.calculateProgress(donut.getProgress());
    }

    @Override
    public void updateProgress(int newProgress) {
        donut.setProgress(newProgress);
    }
}

You get a clean view where the only logic is about layout binding and capturing user interactions (button taps). All the heavy operations are located inside the presenter.

In the my next post, I’ll add some extra actions and I’ll upload the entire project code.