I understand the MVP. However i do not understand model belongs to presentation layer or domain layer. It is said in some resources, mvp only models the presentation layer, in other words model is in presentation layer. https://antonioleiva.com/mvp-android/
However, in other resources https://proandroiddev.com/clean-architecture-data-flow-dependency-rule-615ffdd79e29 , model belongs to domain layer. Which one is correct? Thanks in advance.
You can have different types of models. You can have a DomainModel, a PresentationModel an ApplicationModel etc.
You can use each kind of model in an MVP application if you need to. for example if you have a complex application with multiple Presenters that need to communicate with each other it may be usefull to add an additional ApplicationModel to simplify these communications by adding a Model that has Application specific data and behavior. If you don't have that you can just use a pure DomainModel.
In this article, Martin Fowler says:
Supervising Controller decomposes presentation functionality into two
parts: a controller (often called presenter) and view. The domain data
that needs to be displayed is separate, and following rough MVC
terminology I'll refer to it as a model, although it need not be a
Domain Model.
It's a tricky one, but the basic distintion is that a pure DomainModel usually models some domain (math, banking etc.) and has no presentation or application specific data and/or behavior. You can mix different types of models in your application.
If your application has some complex logic, say that when one thing is selected another thing need to be deselected. you can capture this in a specific Model let's say ApplicationState that is not a DomainModel.
Here's an example. Let's say that we have an application that has Keywords and Tags and displays them to the user. The user can select only a Keyword or a Tag. He can't select both at the same time. Here's a way to do this by sing a Model that captures this application specific logic that is not part of our Domain. We are using the observer pattern here. When this Model changes we raise events.
class ApplicationSate : Subject {
private Tag mSelectedTag;
private Keyword mSelectedKeyword;
public Tag getSelectedTag() { return mSelectedTag; }
public Keyword getSelectedKeyword() { return mSelectedKeyword; }
public Tag HasSelectedTag() { return mSelectedTag != null; }
public Tag HasSelectedKeyword() { return mSelectedKeyword != null; }
public void selectKeyword(Keyword keyword) {
if(hasSelectedTag()) {
mSelectedTag = null;
}
mSelectedKeyword = keyword;
raiseChangedEvent();
}
public void selectTag(Tag tag) {
if(hasSelectedKeyword()){
mSelectedKeyword = null;
}
mSelectedTag = tag;
raiseChangedEvent();
}
}
Here is a good article on GUI architectures.
Related
I am using MVP patterns in Android. And structure looks like below.
Activity - Presenter
|
Fragment
|
CustomView
|
views
So when the presenter gets data from the network, it directly passes data to fragment, and fragment pass data to a custom view and custom view pass data to views.
I am not sure how I can pass data used in views from activity with MVP patterns. If I make presenters for each fragments, custom views, and views, then how can I pass data from activity's presenter to other presenters?
Anyone can help me out with examples?
In order to give a more specific answer to your question you need to give a concrete example. Every solution is valid in a context. I'll give couple of ways you can do this. Choose the one that suits your problem.
Very important part of the MVP is the Model. As far as I'm aware the term Model became popular in programing with the release of the paper Thing Model View Editor which was later refined and renamed to MVC.
The definition of the concept of a Model from this paper is:
A Model is an active representation of an abstraction in the form of
data in a computing system
The Models are represented in the computer as a collection of data
together with the methods necessary to process these data.
With time and experience, people have discovered and specified different types of models.
Here are some of them:
Domain Model
Application Model (read this article for more information)
Presentation Model
MVP, since it derives from MVC, makes two major divisions of responsibilities: Model (the abstraction that represent concepts) and Presentation (View and Presenter to visualize the Model).
Because we have divided the Model from the Presentation, we can have multipe Views that show the same Model different ways. An example of that is a Model that represents Statistical Data that can be shown different ways: a Pie chart, a Bar chart etc. In this example the Statistical Data Model is a Domain Model.
In the example above, the Model will probably be shared between the two View-Presenter pairs , The PieChart and the BarChart. If you use the Observer pattern, when one of the View-Presenter pairs update the StatisticalModel, it will raise changed events, and both View-Presenter pairs will receive notifications for this change and update.
Sometimes an application needs an ApplicationModel. This model can be shared between different View-Presentation pairs. Let's take a look at a verfy simplified example.
Let's say we have a File Browser application like Windows Explorer. This GUI of the application has two major parts: The left panel that shows a Tree of the folders and the middle File-Folder panel. When a folder is selected in the left folders tree panel, files and folders from the selected folder must be shown in the middle panel. We can do this by defining an ApplicationModel that will capture and represent the above logic and be shared between both View-Presentation pairs for the left and middle panels.
Note: I'll omit details to simply the example and write less code
public class ApplicationState {
// singleton, it's evil I know,
// but it's the simplest way without DI or ServiceLocator
private static ApplicationState mInstance = new ApplicationState();
public static ApplicationState getInstance() { return mInstance; }
private Folder mSelectedFolder;
public bool hasSelectedFolder() { return mSelectedFolder != null; }
public Folder getSelectedFolder() { return mSelectedFolder; }
public Folder setSelectedFolder(Folder f) {
mSelectedFolder = f;
RaiseSelectedFolderChangedEvent();
}
// method for registering listeners, raising events etc.
}
public class FoldersTreeViewPresenter {
private ApplicationState mApplicationState;
public void onSelectFolder(FolderView view) {
// select the folder in the view
mApplicationState.setSelectedFolder(view.Folder);
}
}
public class FilesFoldersViewPresenter : ApplicationStateListener {
private ApplicationState mApplicationState;
public FilesFoldersViewPresenter() {
// you can use service locator, dependency injection, whatever
mApplicationState = ApplicationState.getInstance();
mApplicationState.addEventListener(this);
}
private void getFilesAndFoldersFromFileSystem(Folder folder) {
// get from fs
// fill views with them etc.
}
private void clearView() {
// clear the panel
}
public void onApplicationStateChanged() {
if(mApplicationState.hasSelectedFolder()){
getFilesAndFoldersFromFileSystem(mApplicationState.getSelectedFolder());
}
else {
clearView();
}
}
}
In this example we created a shared object that represent the application state and the logic, that our application has a selection that can be changed. In this case the ApplicationState class is part of the Model and is an Application Model. Because it is shared and it's life time is the same as the application (it exists as long as the application is running) it will hold the state. Views and Presenters are created and destroyed, but this class will exist and hold the state, so that when a new View and/or Presenter is created it can check this state and do something.
In my experince people do concentrate on Views and Presenters more, while they should work on their Models. Peronally I use Models alot as it makes things cleaner and the application easier to understand.
Of course, using Models doesn't always work, so when they don't you can use messaging, having one Presenter sending messages to others. Here's an example with the same File Browser app.
public class MessageBus {
// static this time, you can use DI or ServiceLocator with interface
public static void sendMessage(object m) { }
public static void registerListener(MessageListener listener) { }
}
public class FoldersTreeViewPresenter {
public void onSelectFolder(FolderView view) {
// select the folder in the view
MessageBus.sendMessage(new FolderSelected(view.Folder));
}
}
public class FilesFoldersViewPresenter : MessageListener {
public FilesFoldersViewPresenter() {
MessageBus.addListener(this);
}
private void getFilesAndFoldersFromFileSystem(Folder folder) {
// get from fs
// fill views with them etc.
}
public void onMessage(object m) {
if(m instanceof FolderSelected) {
FolderSelected folderSelectedMessage = (FolderSelected)m;
getFilesAndFoldersFromFileSystem(folderSelectedMessage.Folder);
}
}
}
Depending on your specific case, if you can create a nice Model, either a Domain, Application or Presentation, do it. Share this Model thus creating a dependency on the Model from the Presenters instead of creating a dependency between Presenters. This way you have loose coupling between Presenters and you can change them much easier
If you can't use a Model, use a Messages. It's a nice way to decouple Presenters by creating a protocol of messages that are used for communication.
Check this article on using messages for collaboration between components.
Also here are some good articles on GUI architectures:
https://martinfowler.com/eaaDev/uiArchs.html
http://aspiringcraftsman.com/2007/08/25/interactive-application-architecture/
I understand that ViewModel in the Architecture component is for storage and managing data so it will not be lost during config changes.
For example, my activity has nothing do with LiveData or using storage Data. Should I still go through ViewModel? or directly instantiate the Repo Class and call the insertion method? I hope that make sense
An Example of my usage of ViewModel
public class MainViewModel extends AndroidViewModel {
private DataRepo dataRepo;
private LiveData<List<Group>> groupList;
private LiveData<List<Bill>> billList;
public MainViewModel(Application application) {
super(application);
dataRepo = new DataRepo(this.getApplication));
groupList = dataRepo.getGroup();
billList = dataRepo.getBill();
}
public LiveData<List<Group>> getGroupList() {
return groupList:
}
public LiveData<List<Bill>> getBillList() {
return billList:
}
public void insertGroupAndMember(Group group) {
dataRepo.insertGroupAndMember(group);
}
public void insertBills(List<Bill> bills) {
dataRepo.insertBills(bills);
}
public List<Member> getMemberList(Group group) {
return dataRepo.getMembers(group);
}
}
I think you want to use a ViewModel to keep your UI controller as clean as possible. Your viewmodel should call the repo to do simple CRUD operations.
See below snippet from documentation:
Requiring UI controllers
to also be responsible for loading data from a database or network
adds bloat to the class. Assigning excessive responsibility to UI
controllers can result in a single class that tries to handle all of
an app's work by itself, instead of delegating work to other classes.
Assigning excessive responsibility to the UI controllers in this way
also makes testing a lot harder.
Here are some points I would advice you to consider:
MVVM as a pattern has it's roots back in 2000-th, for example, here is Martin Fowler's article about the concept, and in 2005 John Gossman announced the pattern in his blog. Yes, it solves the problem with rotation in android's implementation of the pattern, but this problem could be solved without it. MVVM is actualy needen for separation of presentation state from views that are seen to the end user. As Wiki says -
The view model is an abstraction of the view exposing public properties and commands. Instead of the controller of the MVC pattern, or the presenter of the MVP pattern, MVVM has a binder, which automates communication between the view and its bound properties in the view model. The view model has been described as a state of the data in the model.
So, primarily it is (like all other GUI architectural patterns in their root) about abstraction between view and domain parts of the application, so that they can vary independently and subsequent changes to the system will be cheap.
Instantiating domain objects in the view scope and their subsequent use by the view leads to tight coupling between the view and domain objects, which is a bad characteristic of any system. Also, it is one more reason to change view's internals, because if construction logic of the domain object changes - view will have to be changed too.
If ViewModel is exessive for you (as I can see, its benefits are not relevant for you in this particular case, because the UI is not very complex and it's state is lightweight), consider using a less heavy-weight abstraction, such as MVP. Thus, you will be able to preserve abstraction between view and model in your application (no unwanted coupling) and you won't have to support the code that you don't benefit from.
I have read this impressive article on data modeling in android with clean architecture and MVP.
Now i would like to refactor some existing models that i have in my domain so that they for one do not contain parcelable code (android code) and are streamlined to work in the specific view. You know sometimes we have to alter the model so that it works in a view like for example to get the selected position in a RecyclerView we would add a field called "selectedPosition" to the model. There are many times we need to change the model and then we end up with models that are not pure and a little hard to maintain.
Specifically i have 3 model data for 3 payment systems i am using. All the fields in the 3 models come back different. they have different names for the fields. Can someone show me an example of the architecture used to make all 3 models use a common model ?
Data model
I am sure that your 3 models for 3 payment systems have common features. So you can take this features and put it to interface. Each of your models must implement this interface. In your case it should display a data model.
For example:
class Info {
int id;
String cardNumber;
.......
}
interface ITransactionable { //or abstract class with the common func and prop
void addUserWithCard(String cardNumber, String name);
boolean makeTransaction(\*some params*\);
Info getPaymentUserInfo();
}
class Model1/2/3 implements ITransactionable {
\*In each case methods doing different job but give you same result,
you can take info for your models from servers, clouds, db...*\
}
Domain model
Domain model represent your business logic, manipulating of your data model.
class DonationService {
ITransactionable paymentService;
DonationService(ITransactionable paymentService) {
this.paymentService = paymentService
}
Info makeDonation(int money) {
paymentService.addUserWithCard("4546546545454546", "Vasya");
paymentService.makeTransaction(money);
return paymentService.getPaymentUserInfo();
}
........
}
Each layer must give to next something like API.
Presentation
For example can fill recyclerView with data of each transaction. And take events from view like get detail info about transaction or make new transaction.
You can check this for watching how it can be realized: https://github.com/android10/Android-CleanArchitecture
I was reading an article by Dario Miličić regarding MVP here. I also thoroughly went through the code he provided on git hub. Anyways, i am pretty new to MVP for android and MVP in general, and so I have a question about what he said - "The implementation layer is where everything framework specific happens”. What if i have an android application that deals with Bluetooth? i.e. i have a small application to get a list of bluetooth devices using BluetoothAdapter which is an android class. So I started writing a use cases which was something like this
public interface BluetoothScanInteracotor {
interface View {
void onScanStarted();
void onScanCompleted();
}
void scanForDevices();
}
but then realised that I cant do that because of its framework specific.
How would I go about this?
Forgive me if that's a silly question, but I might be confused about something and I need someone to help me understand.
The CLEAN approach would be to implement a BluetoothDeviceRepository, which could have multiple implementations, one of which would actually access the system resources, but could easily be swapped for one with no external dependencies for test, etc. The Bluetooth device scan results would be converted by repository implementations to return POJO models that represented the information you needed, so that there would be no leakage of the Android system classes into this layer.
The issue with most MVP implementation out there is that they designate Activities and Fragments as Views, and propose to use "Android framework independent" presenters.
This sounds good until one encounters issues like yours - Bluetooth framework is part of Android framework, so it is not clear how to use it in the presenter that shouldn't depend on Android specific classes.
After researching MVx architectures on Android for several years I realized that the only sane conclusion that can be derived is that Activities and Fragments are not views, but presenters.
The more detailed discussion of this subject can be found here: Why Activities in Android are not UI Elements.
Based on this idea I proposed an alternative implementation of MVP in Android: MVP and MVC Architectures in Android.
I have an idea in MVP model that not bad to share with you,
Everything that depends on the OS,should be treated as View, and Logic is Presenter,
For example Activity is a View, we use it to intract with UI ,for example get Text of a Textview, and when we need to process on the text, we make a presenter class for this activity and also an interface to this presenter, then implement the interface in presenter,and call methods of interface in Activity with needed params(for example that Text)
If I want implement it in another OS, i should only change my Activity and get Text in other way,and remain process is same and doesn't change
As you have come to know basics of Clean Architechure. The following example depicts how actual your MVP pattern is implemented.
Example:
interface BaseContract {
interface BaseView {
//Methods for View
void onDoSomething();
}
interface BasePresenter {
void doSomething();
}
}
class BaseMainPresenter implements BaseContract.BasePresenter {
BaseContract.BaseView view;
BaseMainPresenter(BaseContract.BaseView view) {
this.view = view;
}
#Override
public void doSomething() {
if (view != null)
view.onDoSomething();
}
}
class DemoClass implements BaseContract.BaseView {
//Create object of Presenter
/****
* Example :
* BaseMainPresenter baseMainPresenter = new BaseMainPresenter(this);
*/
#Override
public void onDoSomething() {
//Deal with Context here.
}
}
I am designing my Android app to create model/entity classes separately for web service, database, domain, and UI.
I would be transforming my web service objects into domain objects. Then where I have recycler view, I create UI model objects for each row from my domain which would be a subset.
https://developer.android.com/training/articles/perf-tips.html#ObjectCreation
I have also come across https://github.com/PaNaVTEC/Clean-Contacts which is one sample codebase that strictly separates each layer.
I know it's a trade-off between performance and design, but what is recommended? I really like the design, but my concern is the number of objects instantiated.
My take on this is that it is fine to share entities between different layers of your application as long as doing so does not leak implementation details between the layers.
I would happily share a class such as:
public class Product {
private String name;
private BigDecimal price;
private boolean isInStock;
//..
}
But would not share a class such as:
public class MyNetworkLibraryResponse<T> {
private int status;
private Throwable error;
private T data;
//...
}
If you ever decided to swap MyNetworkLibrary for ShineyNewNetworkLibrary you'd soon come unstuck.
Product however would be an integral part of your Domain. Unless you have a need to re-use View code across business domains you'll likely be better off sharing it than causing increased complexity creating a ProductViewModel