preface

In May last year, WHEN I was browsing GitHub, I saw an MVP project called Mosby. After carefully reading the source code and the article introduced by the author, I found that it was really interesting. Although it needed to write more classes and methods, it solved the problem of excessive activity/fragment. Using V/P separation can help improve maintainability. At the end of last year, at the beginning of this year, THE MVP started to be known, and there were articles about its concepts and practices.

MVVM (model-view-ViewModel) corresponds to data Binding on Android. The viewModel-to-view mapping, instead of having to find the View itself and update the field, you update the ViewModel directly after the mapping is created and then reflect it onto the View.

It’s worth noting that MVP and MVVM are both Microsoft concepts that were first used in WPF, but are only now available on Android. This article is not here to introduce these two, so I won’t go over them and get to the point.

In the first article of this series, I mentioned that MVP+MVVM was used in the new application I designed (Flux was also considered, but it was not suitable for Android). Later, when CJJ and I discussed this architecture, I was surprised when he asked me if I had any formal name. Because this combination and application is my own design, so I really did not think of this problem, a Google search, there is such a thing (see resources, the article is very good, I suggest students who are good at English read)!

This is what I want to introduce in this article, MVPVM (Model-view-Presenter ViewModel).

Quick glance

All of the following models, not just beans, but the Model layer, are more like repository or Business Logic.

MVC: The View holds the Controller and passes events to the Controller, which then triggers the Model layer event. The Model updates the data (such as data from the network or database) and triggers the View update event.

At first glance, MVP seems to be a variation of MVC, where C is replaced by P, but if we look at the following figure again:

MVP is actually a wrap for MVC, and the C layer can still be there, handling click events instead of the View, data binding, acting as the observer of the ListView, so that the View can focus on purely visual things. A Presenter avoids the Model triggering an update to the View. The View is completely passive and will only update if the Presenter tells it to update the View, such as showLoading() or showEmpty().

MVVM, through the two-way binding of View and ViewModel, allows us to

  • Update the ViewModel directly, and the View will refresh accordingly
  • The View’s events are passed directly to the ViewModel, which operates on the Model and receives updates.

Why MVPVM

If you read the Clean Architecture source code carefully, you will see that there is already a ViewModel layer in it. If you are familiar with DO (Domain Object), PO (Persistent Object), or VO (View Object), you may know the concept of visibility. Each layer only needs to know what it needs to know. These objects represent completely separate concepts.

For example, the server sends a Date String, but we need to display the relative time description of the Date, such as 1 minute ago, 2 days ago. In order to avoid doing this logic when binding data in the view, the ViewModel will do the conversion instead.

MVVM does omit the boilerplate binding data to the View, but

  • The ViewModel refers to the View, so the ViewModel cannot be reused for other views.
  • It does not solve the problem of View layer overload, only remove data binding, especially for some pages with complex business logic.

Patterns are introduced to improve reusability through pluggability. Loose coupling and small interfaces give maximum reusability, allowing components to be reused.

So there is MVPVM:

In my personal practice:

  • Model: Data and domain modules, including Interactor (UseCase), Repository, Datastore, Retrofit, Realm, DO, part of PO, etc.
  • View: the Activity/fragments.
  • Presenter: Presenter, including Subscriber, and injecting UseCase through Dagger2 to ease coupling.
  • ViewModel: it is transformed from Model, inherits From BaseObservable or SortedList, and most of it directly wraps Model, thus removing the Boilerplate of Mapper. Bind to XML via a Data Binding.

RxJava stream worlds from Presenter Subscriber down, stream in stream out. If you’re already using MVP or Clean Architecture, you’ll find that adding a ViewModel is incredibly simple, while making your code base smaller and more logical.

Then look at the standing of each component in MVPVM.

MVPVM: Model

The actual counterpart is the Repository layer, the Data/Domain Module mentioned in the first article. The specific Model should theoretically be A PO, but most of our scenarios don’t require PO, so it could be a DO for the domain layer.

MVPVM: View

The View doesn’t need to know much about the ViewModel to keep the two decoupled, and the protocol between the two just needs:

  • The ViewModel supports the properties that the View needs to display.
  • A View implements the ViewModel’s observer mode interface (e.g. Listener).

So here the ViewModel to View is a dashed line, not a solid two-way line in MVVM.

MVPVM: Presenter

As in MVP, Presenter stands between the View and Model layers. It is important to note that Presenter is coupled to the ViewModel because Presenter needs to update the Model to the ViewModel, which is the map behavior, and then call the corresponding interface of the View for binding.

Presenter is the only MVPVM that does not require decoupling; it is tightly coupled to the View, ViewModel, and Model layers. If your Presenter is reused by multiple views, you may want to consider whether it is better used as a module, such as a (third party) login.

MVPVM: ViewModel

MVPVM makes the ViewModel reusable because it is no longer tied directly to a particular View, but is presented as a binding of data to the View. Events triggered by user actions by the ViewModel no longer operate directly on the Model; instead, the View takes care of the task flow. The ViewModel itself basically has no field. Instead, the Data Binding finds the property to display by exposing the GET method, which directly calls the corresponding property get method of the held Model.

Ideally, this would be done through a Mapper class, but I think most programmers would be crazy to do this because a lot of fields are just copies, and there are some performance implications (iterating through lists, new objects, converting fields one by one, adding to new lists). So in a middle way, let the ViewModel hold the Model, directly return the specific fields corresponding to the Model in the GET method, and concatenate and special processing in some special fields such as relative time and add some descriptive characters.

Oh, by the way, when it comes to the ViewModel, Data Binding support two-way Binding now oh, see halfthought.wordpress.com/2016/03/23/… Grammar, such as:


Copy the code

Different from @{} of one-way binding, @={} is used. After all, two-way binding is still used with caution. On the one hand, early data flow chaos is hard to understand, and on the other hand, it is easy to appear dead loop.

NO Presenter

The question we sometimes face in MVPS is, do presenters really need to exist at all, especially in static, non-business logic, purely presentable pages, and as a result create a Presenter specifically for the MVP.

Presenter should not be required, as in MVP, V and C are actually conjoined, and in some cases (really pure presentation, or very little business logic) it should be allowed to go to Presenter and let the View do its job. For example, the registration page, I really just want to send the user’s input to the server for verification, why bother to have a presenter mask?

We can not always idealize to choose the so-called best design, in reality necessary circumstances, we should dare to abandon, the most appropriate design is the best design. For this reason, presenters are not mandatory; To DO this, the ViewModel is not necessarily generated by the Mapper, but can return the corresponding fields of the holding DO object.

conclusion

This article talks about MVPVM and its practice in Android. Due to time reasons, it is too late to write a demo to say the specific implementation. We welcome your comments and suggestions. If I have time, I will write a demo on GitHub recently. If you are interested, you can follow it and update it: Markzhai.