Why MVC first?

If you want to better understand MVP, and in the actual development of flexible application, then it is necessary to understand its low version of MVC, they are just one step away, first understand MVC and then learn MVP, MVP advantages can be highlighted, so that the continuous learning will deepen the understanding of MVP.

directory

MVP stuff (1)… Speak with the scene

MVP stuff (2)… A Preliminary study on MVC Architecture

MVP stuff (3)… Using MVC in Android (Part 1)

MVP stuff (4)… Using MVC in Android (Part 2)

MVP stuff (5)… The relationship between the mediator model and MVP

MVP stuff (6)… MVC turned into MVP

MVP stuff (7)… Repository Design analysis

Quickly review

MVP stuff (3)… Using MVC in Android (Part 1)

In the last chapter, we learned the principle of MVC architecture diagram and its evolution process, combined the three objects in MVC through the principle of IS A, has A and dependency injection, and built the basic prototype of MVC framework from scratch.

Spirit and bone, blood and flesh

In the last, our MVC framework has completed the construction of the preliminary, of course, is not a final form of the framework, although three objects through the combination of a link up, but let the framework really work needs to be one of the key mechanism, communication mechanism, like humans, there is a skeleton in light and flesh and blood can’t call it a complete “person”, You also need the nervous system to help you see, hear, and feel.

Communication mechanism

In the object-oriented design of Java, monitoring is a common communication mechanism. In the Observer mode, the objects involved in a monitoring mechanism include: Observer, Obserable; The links involved include: Subscribe, sending events, and handling events.

Implementing a listening mechanism

Since listening is a common means of communication, we started “updating” our framework

Benefits of eavesdropping

Before we begin, there’s still a scenario to illustrate the benefits of eavesdropping. Remember the story of renting a house? In this story, I deliberately ignored the communication mechanism, in order to stay in this chapter, when tenant contact to the mediation, this is a proactive action, tenant is the initiator, when establish contact and mediation, they both leave telephone, intermediary to find the right landlord at the same time, and also left a contact, mediation began waiting for the landlord’s response, this time During this period, the intermediary could do nothing, asking the landlord whether he had considered the matter with a phone call every minute. Then the intermediary would only have two consequences. The landlord was very angry, and a phone call every minute. Direct shielding. Or because the intermediary can only deal with one thing at a time, it can’t deal with the next thing if it can’t be finished, and he will be fired from the company because of low efficiency. Tenants are the same, again and again to ask the agency, found the house? There are also two consequences waiting for him: first, frequent phone calls, expensive waste of resources in building the city; second, because the phone bill is too expensive, I intend to ask once a day, but because the information is not timely, the house is rented by others, that is, the timeliness of the information is low.

In order to avoid the tragedy of the above, the intermediary company to improve the communication mechanism, first of all, from the perspective of tenants to the tenant through active report progress to solve the problem of real-time news, let the tenant for the first time to get the latest situation, secondly, mediation is no longer urged the landlord, but let the landlord think good after notification agents, when a mediation immediately inform after receiving the news of the landlord to the tenant, Through the transformation of these two links, an efficient notification chain is formed.

Add listeners to the MVC framework

Modle is responsible for data production and processing, and after finishing some time-consuming operations, it should actively inform the Controller. Therefore, Model is the object to be observed, while Controller is the object to be observed. It observes every move of Model, and in order to better observe Model’s behavior, The Controller sent an “eye liner” to The Model, whose responsibility was to monitor the Model’s every move.

Step 1: Define an “eye line”

Public interface Observer {}Copy the code

The eyeliner here is an interface for observing objects, but we don’t know exactly what to make it do. In the form of interface, it will have good expansibility in the future. After defining the eyeliner, how to use it?

Remember how views were used in the previous article? It is implemented by Actvity, which means that our “eyeliner” should also be implemented by an object, otherwise it will be of no use. Since the Controller sends an “eyeliner”, it should be used by the Controller. There are two ways to use it, either it has the function of “eyeliner”. That is, is A, or recruit your own spy, Has A.

I am eyeliner, eyeliner is me

**/ Public class TasksController implements Observer{void loadNomData() {}}Copy the code

TasksController, by implementing the Observer interface, has Observer capabilities.

2. I hired a spy

Private Observer Observer = new Observer() {}; private Observer Observer = new Observer() {}; void loadNomData() {} }Copy the code

TasksController, by internally instantiating an Observer interface, indirectly gains Observer capability.

Both of the above can be used to gain observer power, but for extensibility, I prefer the first option.

Step 2: Place eyeliner

Once we have the eyeliner, we also need to place it inside the observer to complete the subscription between the observer and the observed.

public class MainActivity extends AppCompatActivity implments TasksView{ @Override public void onCreate(@Nullable Bundle  savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TasksController = new TasksController(tasksView:this); Model -> View and View -> Model TasksRepository Model = new TasksRepository(tasksView:this); //Controller -> Model model.setController(controller); }}Copy the code

This is the code snippet from the previous article, and it will be improved in the future. Look at the bottom line:

model.setController(controller);
Copy the code

In fact, this step is that the Model owns the Controller. Since our controller now has the responsibility of the observer, and we don’t need to expose the whole controller’s responsibility to the Model in real use, The model only needs the ability of the Controller observer to tell the controller the result in real time, so we can modify this code as:

model.addObserver(observer: controller);
Copy the code

It looks like the parameter is still controller, but I changed the name of the method, so it doesn’t make any difference. I want to say that there is a difference. The change in the name of the method means that the code has changed its business, even though it is all controller, it was all controller before it was changed. I only use the controller observer part, I don’t care about the rest, although you give me all, but it’s my business to use those.

Modified Activity:

public class MainActivity extends AppCompatActivity implments TasksView{ @Override public void onCreate(@Nullable Bundle  savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TasksController = new TasksController(tasksView:this); Model -> View and View -> Model TasksRepository Model = new TasksRepository(tasksView:this); //Controller -> Model model.addObserver(observer: controller); }}Copy the code

Step three, send the event

At this time, the Model has acquired the observer, namely the Controller, so when the Model itself changes, it can immediately notify the Controller. We try to send an event, but before sending the event, don’t forget that the eyeliner has no specific ability, we just define an interface. The specific capabilities of eyeliner should be defined according to the specific business, which does not belong to the architecture and is more focused on the business layer. Here, we simulate that when Model gets data, it will notify Controller that I got the data, so eyeliner will have the function of notifying data OK:

Public interface Observer {// Data OK void onDataComplate(Data Data); }Copy the code

Now the eyeliner is ready, waiting for Model to use, we use Model to send an event

Model :TasksRepository

/** / Public class TasksRepository {// public static ArrayList<Observer> observers = new ArrayList<Observer>(); viod addObserver(Observer observer){ observers.add(observer); } // Get data from server void getTasks() {// Get data from server When the server returns, Data Data = fromServer(); Observers: observers {observer.onDataComplate(data); // Send events for(Observer Observer: observers){observer.onDataComplate(data); } // Get Data from memory cache Data getTaskCache() {} // Get Data from disk cache Data getTaskDiskCache(){} // Save a Data Boolean saveTask(Task Task){} Data orderData(Data Data, int orderType){}}Copy the code

In actual development, the Model is not only monitored for a Controller, but can be monitored by anyone who wants to monitor it. You only need to send an eyeliner to the Model. When the Modle changes, the Model will notify everyone who cares about it, so there is a collection of observers in the Model:

public ArrayList<Observer> observers = 
            new ArrayList<Observer>();
Copy the code

When the Model changes, the collection is traversed to notify all observers, and eyeliner comes in handy here

for(Observer observer : observers){
    observer.onDataComplate(data);
}
Copy the code

Step 4, receive the event

Event handling is the essence of the observer. Since Controller is an observer, event handling should be completed by itself:

Controller :TasksController

/** **/ public class TasksController implements Observer{// void loadNomData() {} }Copy the code

TasksController implements the Observer onDataComplate method. When the Model sends an event, the onDataComplate method receives the event, and we can process the event from there. This is the core of the observer mode, if you need to implement an observer mode, then follow the above four steps, absolutely not confused and will be extremely clear thinking.

What about View?

As mentioned in the above scenario, when the landlord gives a good consideration to the intermediary, the intermediary will inform the tenant of the result in the first time, so how to do it specifically?

public class MainActivity extends AppCompatActivity implments TasksView{ @Override public void onCreate(@Nullable Bundle  savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TasksController = new TasksController(tasksView:this); Model -> View and View -> Model TasksRepository Model = new TasksRepository(tasksView:this); //Controller -> Model model.addObserver(observer: controller); }}Copy the code

Go back to this paragraph in Acivity’s code:

TasksController = new TasksController(tasksView:this);Copy the code

First, we use the constructor to let the controller hold the View. When the controller receives a notification from the Model, it notifies the View immediately, so the TasksController code needs to be improved:

/** **/ public class TasksController implements Observer{// Public TasksController implements Observer{// Public TasksController implements Observer{// view) { this.view = view; } // Receive the event void onDataComplate(Data Data) {// Process the event and then send the event view.ondataback (Data) to the view; } void loadNomData() {} }Copy the code

When we look at handling events, we directly implement the View method, which is called instant notification.

Making the View interface, too, is a key step

So, with the Controller observer mentality, can we make the view an observer, of course we can and we must, let the view observe the Controller change, and the Controller observe the Model change, and then the chain reaction is complete. Look at the relatively complete sample code below:

View :TasksView

/** / public interface TaskView {void onDataBack(Data); // When the list is initialized, the controller is told to load the data void viewCreate(); // upDateList void upDateList(); //just for ui void beginLoadData(); }Copy the code

Activity:

public class MainActivity extends AppCompatActivity implments TasksView{ private TasksController controller; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Controller = new TasksController(tasksView:this); Model -> View and View -> Model TasksRepository Model = new TasksRepository(tasksView:this); //Controller -> Model model.addObserver(observer: controller); viewCreate(); } // Receive the controller event and handle void onDataBack(Data){// Handle the event... } // When the list is initialized, tell the controller to load data void viewCreate(){controller.loadnomData (); Void upDateList(){// Just for UI void beginLoadData(){}Copy the code

Conclusion:

In this article, we improved our framework through the observer mode. By listening, the three objects of MVC form a conveyor belt of events. The events are like having a direction, which generally starts from Model, passes through Controller and finally flows to View. Later we can do whatever we want with our events on this link, and the final receiver, the View, is completely unconcerned, or the View can customize the data it wants before the Model sends the event. To be more precise, we can do a lot of things that we want to do at the three points before the event is sent, in transit, or received, such as some sort of change of data before receiving, which we expose in the way of interface. Here, the introduction of MVC is over, but the construction of the framework has not been completed. In the following content, we will further improve the framework through the way of MVP, and at the same time add some substantive tools to enable the framework to have some basic business functions.