Android App From Scratch Part 1 — Model-View-Presenter

Faruk Toptaş
Android Bits
Published in
5 min readJan 28, 2017

In this tutorial series, I will try to create an RSS Reader app step by step. I aim to explain you about how to write scalable, testable and easy to read/maintain code. And MVP approach that perfectly fits to an Android application.

Through this series I will explain:

  1. How to use Model-View-Presenter in an Android App
  2. Implementing must have libraries
  3. Implementing App Logic
  4. Creating unit tests with JUnit
  5. Creating Android Instrumentations tests with Espresso
  6. Continuous Integration with Travis-CI

I assume that you are familiar with Android Development. So I will not explain each detail. Feel free to ask anything by commenting to my post.

Many people say that MVP is not an architecture. It lets you have layered code by organising. It will be easy to READ, TEST and SCALE the code.

If you need to do same jobs in different places you should have your base classes. BaseActivity, BaseFragment, BasePresenter etc.

Here we go with base classes.

BaseMvpPresenter.kt

/**
* Each presenter must implement this interface
*
*
@param <V> View for the presenter
</V> */
interface BaseMvpPresenter<V : BaseView> {

/**
*
@return true if view is attached to presenter
*/
val isAttached: Boolean

/**
* Called when view attached to presenter
*
*
@param view
*/
fun attach(view: V)

/**
* Called when view is detached from presenter
*/
fun detach()
}

Each presenter is an interface and will implement BaseMvpPresenter Creating the logic over interfaces instead of classes will be useful.

BasePresenter.kt

open class BasePresenter<V : BaseView> : BaseMvpPresenter<V> {

/**
* Attached view
*/
var view: V? = null


override val isAttached = view != null


override fun attach(view: V) {
this.view = view
}

override fun detach() {
view = null
}
}

Each presenter should have attach()/detach() or (bind/unbind) methods to bind the view to the presenter. If an asynchronous job is done we have to check if view is attached or not. So we also need a isAttached()method.

Also view is defined as generic class extends BaseView. By doing this we tell the presenter that it should attach a view that extends the BaseView.

BaseView.kt

interface BaseView

This is an interface that all views should implement. I leave it blank for now. But I will ad some methods here.

BaseActivity.kt

abstract class BaseActivity : AppCompatActivity(), BaseView {


/**
* Layout resource to be inflated
*
*
@return layout resource
*/
@get:LayoutRes
protected abstract val layoutResource: Int


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(layoutResource)
init(savedInstanceState)

}

/**
* Initializations
*/
protected abstract fun init(state: Bundle?)

}

MVP says that your views (Activity, Fragment or ViewGroup) should be as dumb as possible. Because you will keep your logic in presenter classes.

I also created an init() method that triggers in onCreate() for some initialisations.

Note: Don’t use this code in production. We will use dependency injection to create presenter instance. With DI presenter creation will be in BaseActivity Don’t forget this is the first step 😃

Each activity should have layout resource file. I moved it to an abstract class. It is your choice you may not use it.

Now we have our base classes that we need. It is time to add our extra small feature Activity.

Each activity should have a presenter class and a group of interfaces in a contract interface.

MainContract.kt

interface MainContract {

// User actions. Presenter will implement
interface Presenter : BaseMvpPresenter<MainContract.View> {
fun loadHelloText()
}

// Action callbacks. Activity/Fragment will implement
interface View : BaseView {
fun onTextLoaded(text: String)
}

}

This is the signature of our feature. We group methods under two domains.

  1. Presenter interface includes all user actions. (click, swipe, delete etc.)
  2. View interface includes all callbacks and UI changes (show loading, populate a list, show connection error etc.)

Here we have only one action loadHelloText() and a response onTextLoaded(String text) for this action.

MainPresenter.kt

class MainPresenter : BasePresenter<MainContract.View>(), MainContract.Presenter {

private val helloTexts = listOf("BONJOUR", "HOLA", "HALLO", "MERHABA", "HELLO", "CIAO", "KONNICHIWA")

override fun loadHelloText() {
val random = Random()
val hello = helloTexts[random.nextInt(helloTexts.size)]
view?.onTextLoaded(hello)
}
}

I extended BasePresenter and say that MainContract.View is attached to the activity. Then implement MainContract.Presenter to our presenter. So our presenter has all possible user actions.

Layout for the activity:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="me.topas.rssreader.MainActivity">

<TextView
android:id="@+id/tvHello"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="20sp" />
</RelativeLayout>

MainActivity.kt

class MainActivity : BaseActivity(), MainContract.View {


private lateinit var mPresenter: MainContract.Presenter

override val layoutResource = R.layout.activity_main

override fun init(state: Bundle?) {
mPresenter = MainPresenter()
mPresenter.attach(this)
mPresenter.loadHelloText()

tvHello.setOnClickListener {
mPresenter.loadHelloText()
}
}

override fun onTextLoaded(text: String) {
tvHello.text = text
}

override fun onDestroy() {
super.onDestroy()
mPresenter.detach()
}


}

I created a presenter instance then attached it. DO NOT do it in production code. Because I will do it with DI in next parts.

After attaching, loadHelloText() method of presenter is called. Presenter decides what to show in hello text, then pass it to the view with onTextLoaded(String text) callback.

Here is the source code of this part:

This is the very basic implementation of MVP. In the next parts I will give more details and real code. You can find different examples of MVP below:

You can go on reading with Part2

If you liked the article, please 👏👏👏 so more people can see it! Also, you can follow me on Medium

--

--