# Android Architecture: MVP Pattern ###### tags: `Android Architecture` [TOC] ## What is MVP? ![](https://i.imgur.com/lCaQtYF.png =500x350) MVP stands for Model-View-Presenter. ### Each Part **Model:** It is the data layer, responsible for managing the business logic and handling network or database API. **View:** It is the UI showing the data obtained from model. The view will implement the interface the presenter has. Furthermore, it still needs an instance of the presenter. **Presenter:** The presenter is a controller that really does not know which view it is going to handle now nor after. It just sends the information to whoever request it. In order to achieve this attribute, it has an interface which is implemented by the Views, the presenter might handle. ### How it works? 1. Presenter will have an interface inside the class. 2. The Interface inside Presenter will be implemented by the Views ## MVP Coding Parts ### 1. Model #### Information Main Structure: ```java== import com.google.gson.annotations.SerializedName; public class Country { @SerializedName("name") public String countryName; @SerializedName("capital") public String capitalName; @SerializedName("region") public String regionName; } ``` #### Interface used in >Why is it ++*@GET("all")*++? That is because the url was: https://restcountries.eu/rest/v2/++**all**++[color=red] ``` java== public interface CountriesApi { @GET("all") Single<List<Country>> getCountries(); } ``` #### Retrieve information from API: CountriesService Class used Retrofit library to get information from the API. ``` java== public class CountriesService { public static final String BASE_URL = "https://restcountries.eu/rest/v2/"; private CountriesApi api; public CountriesService() { Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); api = retrofit.create(CountriesApi.class); } public Single<List<Country>> getCountries(){ return api.getCountries(); } } ``` ### 2. View The view will be implementing the interface made in the presenter, in order to let it know which view it is dealing at the moment. As it is ++implementing++ the interface, we have to remember to overridethe methods. In this case **setValues** and **onRetry**. ```java== import android.content.Context; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.Toast; import java.util.ArrayList; import studio.zc.androidarchitecture.R; import studio.zc.androidarchitecture.model.Country; public class MVPActivity extends AppCompatActivity implements MVPPresenter.viewDealer{ private RecyclerView rv_country; private MVPAdapter mvcAdapter; private MVPPresenter mvpPresenter; private Button btn_retry; private ProgressBar pb_bar; public interface onClickI{ void onClick(int i); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvp); setTitle("MVP"); this.rv_country = findViewById(R.id.rv_country); this.btn_retry = findViewById(R.id.btn_retry); this.pb_bar = findViewById(R.id.pb_bar); this.mvcAdapter = new MVPAdapter(new onClickI() { @Override public void onClick(int i) { Toast.makeText(MVPActivity.this, "" + i, Toast.LENGTH_SHORT).show(); } }); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); this.rv_country.setAdapter(mvcAdapter); this.rv_country.setLayoutManager(layoutManager); mvpPresenter = new MVPPresenter(this); } //viewDealer Override Methods @Override public void setValues(ArrayList<Country> country) { this.mvcAdapter.setCountryList(country); this.btn_retry.setVisibility(View.GONE); this.pb_bar.setVisibility(View.GONE); this.rv_country.setVisibility(View.VISIBLE); } @Override public void onRetry(View view) { mvpPresenter.onRetry(); this.btn_retry.setVisibility(View.GONE); this.pb_bar.setVisibility(View.VISIBLE); this.rv_country.setVisibility(View.GONE); } @Override public void onError() { Toast.makeText(this, R.string.error_msg, Toast.LENGTH_SHORT).show(); this.btn_retry.setVisibility(View.VISIBLE); this.pb_bar.setVisibility(View.GONE); this.rv_country.setVisibility(View.GONE); } //Intent public static Intent getIntent(Context context){ return new Intent(context, MVPActivity.class); } } ``` ### 3. Presenter Inside the presenter we have to state an interface, which will be implemented by the view it is dealing at the moment. :::warning **Note:** There is a ++**big difference** here with the MVC++ and that is you do not need a reference as MVPActivity, but you need one as viewDealer(the interface). This means that whichever view is given, it can still run, get information and send it over. And when the view obtains the information, it will handle it. ::: ```java== import android.view.View; import java.util.ArrayList; import java.util.List; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.schedulers.Schedulers; import studio.zc.androidarchitecture.model.CountriesService; import studio.zc.androidarchitecture.model.Country; public class MVPPresenter { private viewDealer view; private CountriesService service; public interface viewDealer{ void setValues(ArrayList<Country> country); void onRetry(View view); void onError(); } public MVPPresenter(viewDealer view) { this.view = view; service = new CountriesService(); fetchCountries(); } public void fetchCountries(){ service.getCountries() .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(new DisposableSingleObserver<List<Country>>() { @Override public void onSuccess(List<Country> value) { ArrayList<Country> rv_list = new ArrayList<>(); rv_list.addAll(value); view.setValues(rv_list); } @Override public void onError(Throwable e) { view.onError(); } }); } public void onRetry(){ fetchCountries(); } } ``` ## Advantange & Disadvantages **Advantage:** * The ++Presenter++ is **NOT** bonded to the view like the MVC architecture where controller is highly bonded to the view. >**Main advantage?** You can swap views and use the same presenter for all of them. [color=pink] >**How?** The presenter has an interface which it does not know which View will implement it. Moreover, the presenter will have instance of the interface, meaning it can be switch with whichever view implements the interface.[color=orange] **Disadvantage:** * The View is still highly dependent on the presenter, as it has the instance of it. This means you can only use specific presenter for each view. * Presenter will update values as soon as values are obtained. >**Why is the last one a problem?** What if you are using an app, clicked something which it is still running and when you are doing something else the view is updated suddenly, it will ++**INTERRUPT the user experience**++. [color=red]