Android MVP for beginners

Abhishek Pathak
5 min readFeb 10, 2023

--

In this article you will learn MVP building blocks and it’s implementation, usage and it’s disadvantages.

What is MVP?

The MVP architecture pattern allows separating the presentation layer(UI) from the logic so that everything about how the UI works is separated from how we represent it on screen. Ideally, the MVP pattern would achieve that the same logic might have completely different and interchangeable views.

  • Model: Layer for Data related work. It is responsible for handling the domain logic(real-world business rules) and communication with the database(eg. CRUD data from sqlite/ Room DB/ Any ORM) and network layers(eg. fetching API from Volley/Retrofit).
  • View: UI(User Interface) layer. This layer directly interact with User. It provides the visualization of the data and keep a track of the user’s action in order to notify the Presenter.
  • Presenter: Fetch the data from the model and applies the UI logic to decide what to display. It manages the state of the View and takes actions according to the user’s input notification from the View.

Why use MVP?

In Android, we have a problem arising from the fact that Android activities are closely coupled to both UI and network layer. We can find extreme examples such as making API calls in MainActivity and also setting UI stuff in activity and there we make our Activity like a god’s Activity of more than 400–500 lines… :)

That’s the biggest problem when you have to redesign the app or extend the app with some more feature so maintenance is almost impossible. For an application to be easily extensible and maintainable, we need to define well-separated layers. With MVP we take most of the logic out from the activities so that we can test it without using instrumentation tests.

How to implement MVP for Android

For this article, I’ve implemented a very simple example that you may find on my GitHub with a login screen and a main screen. For simplicity purposes, the code in the article is in Kotlin.

Also I am going through one simple example using MVP implementation

Step 1: Let’s create the architecture packages MVP each layer

Step 2: Data Layer Start creating your app from Data layer, so i am creating response classes and as I am using Volley for API call so creating a volley handler too and kept the constant separately in object.

object Constant {
const val API_URL = "https://dog.ceo/api/breeds/image/random"
}

Now Let’s make Data response class as I am using Random Dog API so my response class look like this

data class DogResponse(
val message: String,
val status: String
)

Now I am moving to make a Volley Handler to handle the API request using Volley network library.

class VolleyHandler(private val context: Context) {
fun makeAPICallToGetRandomDog(callback: OperationalCallback) {
val requestQueue: RequestQueue = Volley.newRequestQueue(context)
val request = StringRequest(
Request.Method.GET,
API_URL,
{
// success block
val apiResponse = Gson().fromJson(it, DogResponse::class.java)
callback.onSuccess(apiResponse)
},
{
//Error block
callback.onFailure(it.toString())
}
)
requestQueue.add(request)
}
}

Now to communicate between Data layer and Presenter once you get the API result, I need a listener to listen the result so making an interface that will provide update once API return result

interface OperationalCallback {
fun onSuccess(dogResponse: DogResponse)
fun onFailure(message: String)
}

Step 3: Let Implement Presenter Layer

As this is simple MVP so making a simple MVP interface

interface DogMVP {
interface DogPresenter {
fun getDog()
}

interface DogView {
fun setResult(dogResponse: DogResponse)
fun onLoad(isLoading: Boolean)
fun showError(message: String)
}
}

Now it’s time to create presenter to provide implementation of MVP presenter method

class DogPresenter(
private val volleyHandler: VolleyHandler,
private val dogView: DogMVP.DogView
) : DogMVP.DogPresenter {

override fun getDog() {
dogView.onLoad(true)

volleyHandler.makeAPICallToGetRandomDog(object : OperationalCallback {
override fun onSuccess(dogResponse: DogResponse) {
dogView.onLoad(false)
dogView.setResult(dogResponse)
}

override fun onFailure(message: String) {
dogView.onLoad(false)
dogView.showError(message)
}
})
}
}

Step 4: Last step let’s Implement View Layer

I am making a simple UI for showing dog random picture so just taking a Imageview and progressbar and a button

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.MainActivity">

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/imageOfDog"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="20dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@+id/btnGetRandomDog"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="100dp"
android:layout_height="100dp"
android:indeterminate="true"
app:indicatorColor="#FBC02D"
app:indicatorSize="100dp"
app:trackThickness="10dp"
app:trackColor="#4A148C"
android:id="@+id/loader"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:indicatorDirectionCircular="clockwise"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnGetRandomDog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#2196F3"
android:text="Get New Dog"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Now it’s time to provide body to all MVP view methods and call presenter from UI to make the implementation complete

class MainActivity : AppCompatActivity(), DogMVP.DogView {
private lateinit var binding: ActivityMainBinding
private lateinit var presenter: DogPresenter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initPresenter()
binding.btnGetRandomDog.setOnClickListener {
presenter.getDog()
}
}

private fun initPresenter() {
presenter = DogPresenter(VolleyHandler(this), this)
}

override fun onLoad(isLoading: Boolean) {
if (isLoading) {
binding.loader.visibility = View.VISIBLE
} else {
binding.loader.visibility = View.GONE
}
}

override fun setResult(dogResponse: DogResponse) {
Glide.with(this)
.load(dogResponse.message)
.error(android.R.drawable.ic_dialog_alert)
.placeholder(R.drawable.ic_launcher_background)
.into(binding.imageOfDog)
}

override fun showError(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}

Yeah we are all done to test this, let’s go

I got this result

Disadvantages of MVP

  • One view require one presenter so you need as many as presenter as view like activities or fragments.
  • Presenter have reference of View so it is tightly coupled with view and that’s the biggest drawback of MVP architecture.
  • It doesn’t contains anything related to lifecycle aware of Views like Activities or fragments.

Conclusion

Separating UI from logic in Android is not easy, but the MVP pattern makes it easier to prevent our activities end up degrading into very coupled classes consisting of hundreds or even thousands of lines. In large Applications, it is essential to organize our code well. Otherwise, it becomes impossible to maintain and add new features in the existing codebase.

Nowadays, there are better alternatives like MVVM architecture you should also try. Here is my one of the MVVM article for beginners.

Thank you for reading my article. I really appreciate your response.

Clap if this article helps you. If I got something wrong, please comment for improve.
let’s connect on
Linkedin , GitHub

--

--