- 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 structureFor 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 architectureThis 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 layerFirst 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 O Ntasksloaded (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) { // According to TaskID to find out the corresponding task ... if (task! = null) { callback.ontaskloaded (Task); } else { callback.ondatanotavailable ();} } @Override public void Savetask (@NonNull task Task) { checknotnull (Task); Sqlitedatabase db = Mdbhelper.getwritabledatabase (); Contentvalues values = new Contentvalues (); 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 layersSince 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;public interface 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;public Interface 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 available 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> {void Showemptytaskerror (); void Showtaskslist (); void Settitle (String title); void SetDescription (String description); Boolean isActive (); } interface Presenter extends Basepresenter {void CreateTask (string title, string description); void Updatetask (string title, string description); void Populatetask (); The
is clearly visible here in the view layer that handles some data display operations, while in the presenter layer, the task is saved, updated, and so on. The implementation of the
presenter Layer Looks at how presenter is implemented.
public class Addedittaskpresenter implements Addedittaskcontract.presenter, Tasksdatasource.gettaskcallback {.. Public Addedittaskpresenter (@Nullable String taskId, @NonNull tasksdatasource tasksrepository, @NonNull Addedittaskcontract.view addtaskview) {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 new Runtimeex Ception ("Populatetask () was called and task is new."); } mtasksrepository.gettask (Mtaskid, this); } @Override public void ontaskloaded (Task Task) {//The view 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 layerThe 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 prot ected 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 New Addedittaskpresenter (TaskId, Injection.providet Asksrepository (Getapplicationcontext ()), addedittaskfragment); } ......}
The Provides a very simple function for activity, first creating a fragment object and adding it to the activity. The presenter object is then created and fragment, which is the view, is passed to presenter.
Look at the implementation of the view below, that is, fragment.
public class Addedittaskfragment extends Fragment implements Addedittaskcontract.view {... @Ove Rride 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 for 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 note 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.
The separation between activity and Fragment fits nicely with this implementation of mvp:the activity are the overall cont Roller that creates and connects views and presenters. Tablet layout or screens with multiple views take advantage of the 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.
SummarizeWith 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.