Overview
The MVP (Model View Presenter) architecture evolved from the well-known MVC (Model View Controller) architecture. For Android applications, the development itself can be seen as an MVC architecture. The XML file is typically considered a view role in MVC in development, while activity is considered a controller role in MVC. However, in many cases, the activity can not fully act as a controller in practical application development, but a combination of controller and view. The activity is responsible for the display of the view and the handling of the business logic. This allows the code to reach thousands of lines in the activity, or even thousands of of rows are not enough, and the activity looks bloated. Therefore, the MVC architecture is not very suitable for Android development. Here's an introduction to the MVP architecture and a look at Google's official example of the MVP architecture.
Introduction to the MVP architecture
For an application we need to abstract all facets of it, and in the MVP architecture it isolates the UI interface and data, so our application is divided into three levels.
- View: It is also the views layer, which is only responsible for the presentation of the data and provides a friendly interface to interact with the user. Activity or fragment is often used as the view layer in Android development.
- Model: For the model layer is also the data layer. It is different from the model in the MVC architecture, where it is more than just the data models. In the MVP architecture, the model is responsible for accessing data, such as reading and writing the database, requests for data from the network, and so on.
Presenter: For Presenter layer He is the bridge between the view layer and the model layer and processes the business logic. Model and view cannot interact directly in the MVP architecture. So in the presenter layer it will get the required data from the model layer and do some proper processing to show it to the view layer. This isolates the view from the model by presenter so that there is no coupling between the view and the model, and the business logic is drawn away from view.
Here's a look at the relationship between the various levels of the MVP through the MVP chart.
In the MVP architecture, these three layers are abstracted separately into their respective interfaces. The interfaces are used to isolate the layers, and the presenter of the view and model depend on their respective interfaces. This conforms to the principle of interface isolation, and it is interface-oriented programming. A view interface is included in the presenter layer and is dependent on the model interface to associate the model layer with the view layer. For the view layer, a Presenter member variable is held and only the calls to the presenter interface are retained, and the specific business logic is all handled by the presenter interface implementation class.
Official MVP Architecture Analysis
Project Introduction
There is some understanding of the MVP architecture, and at the front-end time Google gives some implementation of the app development architecture.
The project address is: Https://github.com/googlesamples/android-architecture.
Go to the readme here to see what Google has to offer for Android development architectures.
The implementation of the above five development architectures represents the projects that have been completed so far, while the following two represent projects in progress. Now let's start by introducing these architectures.
- TODO-MVP: the base MVP architecture.
- Todo-mvp-loaders: Based on the implementation of the MVP architecture, the loaders architecture is used in the Data acquisition section.
- Todo-mvp-databinding: Based on the implementation of the MVP architecture, data binding components are used.
- Todo-mvp-clean: The implementation of the clean architecture based on the MVP architecture.
- Todo-mvp-dagger2: Based on the MVP architecture, the dependency injection dagger2 is used.
- Dev-todo-mvp-contentproviders: Based on the mvp-loaders architecture, Contenpproviders is used.
Dev-todo-mvp-rxjava: An abstraction based on the MVP architecture for concurrent processing of programs and data layers (model in MVP).
As you can see from the above introduction, the implementation of all the architectures given by the authorities is ultimately based on the MVP architecture. So here's an analysis of the above based MVP architecture TODO-MVP.
analysis of the project structure
For this project, it implements the function of a memo. Added to the to-do list for unfinished tasks in the work. We are able to mark completed tasks in the list, to be able to modify the task content on the task Detail page, and to count the completed tasks and the number of unfinished tasks.
First, here's a look at the overall project structure of TODO-MVP.
As you can see, the overall project contains an app src directory, four test directories. In the SRC directory, the way the code is organized is broken down by function. There are four features in this project, namely: Add edits to Tasks (addedittask), Task completion statistics (statistics), Task Details (taskdetail), Task List display (tasks). For the data packet, it is the source of the project, the database reads and writes, the network request operation is stored in the package, is also the model layer in the MVP schema. The Util package below is a tool class for storing some of the items used in the project. Two interfaces Basepresenter and Baseview are stored at the outermost layer. They are the base class for the presenter layer interface and the view layer interface, and all the presenter and view layer interfaces in the project inherit from both interfaces.
Now go into the function module and see how the class is divided within the module. The classes are divided into xxactivity,xxfragment,xxpresenter,xxcontract under each function module. It is these classes that make up the presenter layer and the view layer in the project. The following is an analysis of how the MVP architecture is implemented in this project.
the implementation of the MVP architecture
This is only a macro focus on the implementation of the MVP architecture, the internal details of the code is not in the specific analysis. Then take the task of adding and editing this feature to see how the official Android implementation of the MVP architecture.
implementation of the model layer
First we start with an analysis of the most inner layers of the MVP architecture, which is the corresponding model layer. The contents of the corresponding data package in this project. The encapsulation of some data sources, such as databases, under data. The Tasksdatasource interface is provided for the presenter layer. Take a look at this Tasksdatasource interface here.
public Interface tasksdatasource { interface Loadtaskscallback {void ontasksloaded (list<task> tasks); void ondatanotavailable (); } interface Gettaskcallback {void ontaskloaded (Task Task); void ondatanotavailable (); } void gettasks ( @NonNull Loadtaskscallback callback); void gettask ( @NonNull String TaskId, @NonNull Gettaskcallback callback); void savetask ( @NonNull task Task); ......}
The implementation of the Tasksdatasource interface is Taskslocaldatasource, and the method in Tasksdatasource is the operation of some additions and deletions to the database. In Tasksdatasource, the two internal interfaces Loadtaskscallback and Gettaskcallback are the callback interfaces of the model layer. Their true realization is in the presenter layer. The data is passed to the presenter layer after the data has been successfully acquired or transmitted through this callback interface. Similarly, if the acquisition fails, the presenter layer is also notified through the callback interface. Here's a look at the implementation class for Tasksdatasource.
Public class taskslocaldatasource implements tasksdatasource {......@Override Public void Gettask(@NonNull String taskId, @NonNull Gettaskcallback callback) {//The corresponding task is trained according to TaskID......if(Task! =NULL) {callback.ontaskloaded (Task); }Else{callback.ondatanotavailable (); } }@Override Public void Savetask(@NonNull Task Task) {checknotnull (Task); Sqlitedatabase db = Mdbhelper.getwritabledatabase (); Contentvalues values =NewContentvalues (); Values.put (taskentry.column_name_entry_id, Task.getid ()); Values.put (Taskentry.column_name_title, Task.gettitle ()); Values.put (Taskentry.column_name_description, Task.getdescription ()); Values.put (taskentry.column_name_completed, task.iscompleted ()); Db.insert (Taskentry.table_name,NULL, values); Db.close (); } ......}
Here we are adding and editing functions for tasks, so we omit a lot of code. You can see the Gettask method implemented in Taskslocaldatasource, in which the Gettaskcallback callback interface within the Tasksdatasource is passed in. The implementation of the Gettask method shows that the callback method is called after the query to the task, and if the two callback methods are implemented in the presenter layer, the data is passed to the presenter layer. A callback method is also used to perform the corresponding operation for a query to a task that is empty.
The same is true for data obtained through a network request, the data that is successfully requested can be passed to the presenter layer through the callback method, and the corresponding operation can be performed by the callback method for network request failure.
interfaces provided by the presenter and view layers
Since the interfaces provided in the presenter and view layers are in a class, here is a first look at what interfaces they provide to the outside. First, look at the two base class interfaces Basepresenter and Baseview.
Basepresenter
package com.example.android.architecture.blueprints.todoapp;publicinterface BasePresenter { void start();}
There is only one start method in Basepresenter. This method typically performs the task of fetching data from the model layer in presenter and invoking the view interface display. This method is typically called in the Onresume method in fragment.
Baseview
package com.example.android.architecture.blueprints.todoapp;publicinterface BaseView<T> { void setPresenter(T presenter);}
There is only one Setpresenter method in Baseview, and there is a presenter object for the view layer. And Setpresenter is the presenter in the view is initialized.
Addedittaskcontract
In the MVP architecture given by Android, the presenter interface and the view interface are provided in a different form than we normally see on the web. Here the interface between presenter and view is placed in the Addedittaskcontract class. This allows us to see more clearly what functions are available in the presenter Layer and view layer, which facilitates our future maintenance. Here's a look at this addedittaskcontract class.
Public interface addedittaskcontract { interface View extends baseview<Presenter> { voidShowemptytaskerror ();voidShowtaskslist ();voidSettitle (String title);voidSetDescription (String description);BooleanIsActive (); } interface Presenter extends basepresenter { voidCreateTask (string title, string description);voidUpdatetask (string title, string description);voidPopulatetask (); }}
It is clear here that some data display operations are handled in the view layer, while in the presenter layer the task is saved, updated, and so on.
implementation of presenter layer
Let's take a look at how the presenter is implemented.
Public class addedittaskpresenter implements addedittaskcontract. Presenter, tasksdatasource. Gettaskcallback {...... Public Addedittaskpresenter(@Nullable String taskId, @NonNull tasksdatasource tasksrepository, @NonNull addedittaskcontract.view addtaskvi EW) {mtaskid = TaskId; Mtasksrepository = Checknotnull (tasksrepository); Maddtaskview = Checknotnull (Addtaskview); Maddtaskview.setpresenter ( This); }@Override Public void Start() {if(Mtaskid! =NULL) {populatetask (); } } ......@Override Public void Populatetask() {if(Mtaskid = =NULL) {Throw NewRuntimeException ("Populatetask () was called and task is new."); } mtasksrepository.gettask (Mtaskid, This); }@Override Public void ontaskloaded(Task Task) {//The view May is able to handle UI updates anymore if(Maddtaskview.isactive ()) {Maddtaskview.settitle (Task.gettitle ()); Maddtaskview.setdescription (Task.getdescription ()); } } ......}
Here you can see that in addedittaskpresenter it not only implements its own presenter interface, but also implements the Gettaskcallback callback interface. And in the presenter contains the model layer Tasksdatasource object Mtasksrepository and the view Layer Addedittaskcontract.view object Maddtaskview. The entire business logic is then handled in presenter.
As can be seen from the business process of presenter, first call the model layer interface Gettask method, through TaskID to query task. After querying to a task, the callback interface gettaskcallback of the model layer is implemented in the presenter layer. At this time in the presenter layer through the Ontaskloaded method to get to the task object, and finally by invoking the view layer interface to achieve the data display.
implementation of the view layer
The implementation of the view is in fragment, while in activity it completes the addition of the fragment, presenter creation operation. Let's look at the Addedittaskactivity class first.
Public class addedittaskactivity extends appcompatactivity { @Override protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setcontentview (r.layout.addtask_act); ......if(Addedittaskfragment = =NULL) {addedittaskfragment = Addedittaskfragment.newinstance (); ...... Activityutils.addfragmenttoactivity (Getsupportfragmentmanager (), Addedittaskfragment, R.id.contentFrame ); }//Create the presenter NewAddedittaskpresenter (TaskId, Injection.providetasksrepository (Getapplicationcontext ()), Addedittaskfragment); } ......}
The functionality provided for the activity is also very simple, first creating the fragment object and adding it to the activity. The presenter object is then created and fragment, which is the view, is passed to presenter.
Here's a look at the implementation of view, which is fragment.
Public class addedittaskfragment extends Fragment implements Addedittaskcontract. View {......@Override Public void Onresume() {Super. Onresume (); Mpresenter.start (); }@Override Public void Setpresenter(@NonNull addedittaskcontract.presenter Presenter) {Mpresenter = Checknotnull (presenter); } ......@Override Public void Settitle(String title) {Mtitle.settext (title); } ......}
In this case the source code is not too much posted. In fragment, the presenter object is obtained through Setpresenter. The processing of the business is accomplished by invoking the method in presenter. In fragment, however, there are just a few things to do with the UI. This reduces the amount of code for the fragment type and makes the logic clearer.
We notice that the implementation of the view layer is done through fragment. Why do you use fragment instead of activity for the view implementation? Take a look at how the official explanation is.
betweenandwithoftheisthethatandandorwithofthe Fragments framework.
Here there are two explanations for the reasons for using fragment.
- The separation of activity and fragment is ideal for the implementation of the MVP architecture. In this case, the activity as a global controller will be associated with the presenter view.
- Using fragment is more advantageous for tablet layouts or multi-view screens.
Summary
With the use of the MVP architecture, it can be seen that the responsibilities between the levels are more single and clear, and the coupling of the code is reduced to a great extent. For an example of the official MVP architecture, Google also made it clear that the examples of the architectures they gave were only as a reference, not a standard. So there is more room to expand the base MVP architecture. For example, combine the examples given by Google. We can build a clean architecture by using Dagger2,rxjava on the basis of the MVP architecture. is also a good choice.
Android Official MVP Architecture interpretation