I am working on an Android test project composed of 3 main parts, each of which developed following the MVP pattern.
These parts are nested into each other and I would like to know if the strategy I am following is the correct/best one or not
Structure:
Book: ViewPager containing different Pages
Page: Custom LinearLayout containing multiple Items
Item: Custom View (in this example a simple button)
Each part uses a MVP structure (so for example for Book I made BookPresenter, BookView and BookModel, and the same for Page and Item)
As a user case I would like to keep track of how many times the user clicks the button and for each time change the Page background to a random color, and when the user reaches the 10th click tell the BookPresenter to go to the second page.
To do so I set up things so
BookView creates the BookPresenter, which in turns creates each PageView.
Each PageView creates the PagePresenter which in turns creates the ItemView (which ultimately creates the ItemPresenter)
In all this, the BookPresenter has a reference to the PagePresenter, and the PagePresenter has a reference to the ItemPresenter, so when some actions need to take place they can communicate to the child or the parent presenter in the structure
Now the question:
Is this the right way to set up a system with nested MVPs?
Because if I then want to have a PageView but instead of in a Book I need to put it in a Newspaper (other class with some alternative behaviour to Book) I still would need to recreate the whole chain of dependencies with Presenters and all the rest...
How does a “Child-Presenter” communicate with its “Parent-Presenter”? They don't (directly, not via EventBus)
From my point of view such Parent-Child relations are code smells because they introduce a direct coupling between both Parent and Child, which leads to code that is hard to read, hard to maintain, where changing requirement affects a lot of components (hence it’s a virtually impossible task in large systems) and last but not least introduces shared state that is hard to predict and even harder to reproduce and debug.
So far so good, but somehow the information must flow from Presenter A to Presenter B: How does a Presenter communicate with another Presenter? They don’t! What would a Presenter have to tell another Presenter? Event X has happened? Presenters don’t have to talk to each other, they just observe the same Model (or the same part of the business logic to be precise). That’s how they get notified about changes: from the underlying layer.
Whenever an Event X happens (i.e. a user clicked on a button in View 1), the Presenter lets that information sink down to the business logic. Since the other Presenters are observing the same business logic, they get notified by the business logic that something has changed (model has been updated).
Source: http://hannesdorfmann.com/android/mosby3-mvi-4
So let's apply this on your example.
You should have something like a Readable (if you want to make an abstraction over Book implements Readable and NewsPaper implements Readable). With Readable.getPageCount() you get the number of pages for ViewPager. With Readable.getCurrentPage() you get the current Page. Then you need some kind of Observer Pattern to be notified whenever the page is changed. You also need a Listener / Observer pattern when the user clicks on a button in ItemView. Such a click would be an Event X from the graphic above. On click on the button you let the information flow down through Presenter to your business logic which changes the Readable object. This change will then notify observers of this Readable object like PagePresenter that then updates the PageView to set the background color of the page.
So the key is: communicate via Business Logic, instead of some View to View or Presenter to Presenter communication.
Hope that helps.
Related
When working with Bottom Sheets and Dialog how to perform operation:
Use a SharedViewModel with fragment that created this bottom sheet?
Don't use a ViewModel at all?
Creating a separate ViewModel for the BottomSheet?
Any other approach that is best practice
If the bottom sheet/dialog is tightly bound to your "host" fragment (it shares some specific live data), and it is never going to be created from some other fragment, then it's OK to use a shared view model.
If the dialog is dead simple (like one input + 2 buttons), then the viewmodel might not be needed
If the dialog really needs a viewmodel (i.e. it fetches and displays some dynamic data), then a separate viewmodel makes sense
I'll go with the first approach by using a ShareViewModel, but if you understand the underlying layer, shared ViewModel is also ViewModel it's just a name convention we gave it to them.
Also sometimes it becomes tedious to write separate ViewModel to deal with fragments and bottom sheet where a MainActivity ViewModel can also do the exact same thing.
What I meant, in order to avoid complexity I use one view model per activity. Now, whenever I want to execute something in fragment or bottom sheet I just pass the view model in the constructor itself. Many people will think this is bad practice but it's not coz as per the concept of view model it will only be created and destroyed in accordance with the activity's lifecycle and only one instance will be created all along. Also by doing this, I can use Dependency injection with the fragment (I don't think that DI works with navigation component but I think you got my point).
I have an app designed using MVP pattern. But sometimes I'm not sure that all of our implementations stick to the MVP best practices. Although it's not always possible to work by the book I'm trying to figure out where should be the logic that deals with non user interactions.
For example:
I have to detect the offset of vertically scrolling RecyclerView. When scrolling reaches 20% of the content height (roughly) I should show a pop up. Now, my logic would be (pseudocode)
1. Presenter sets View.setVerticalOffsetTriggeringLimit(1000 pixels)
2. View triggers view event and call Presenter.offsetForPopUpReached()
3. Presenter triggers View.showPopUp()
4. pop up is shown
Pros and Cons? Is there a way to do it better while still have testable code? Is the System itself a "user" that should use presenter as a middle layer?
All UI logic belong to View. Presenter has to have only interaction logic between Model and View. The point is, that View may differ - it can either be a UI, or, some module, sending commmands via sockets. The point is, that in both cases 'presentation logic' - as View interact with data remains the same, thus has to be moved into Presenter. Popups , margins, etc, is a View implementation details.
Handy practice- create Presenter as singleton and inject it by DI into Activity, which, in turn, implements View and connect it to that View.
You can rid of Model by sending events from Presenter via EventBus (sticky events). If you do so, event will be waiting until Activity receive it (metigate Activity lifecycle). I encountered that approach little while ago.
I'm building one Android app using MVP, and I have one question about this pattern.
Say I have one screen for creating a new person. This screen will show one EditText for inserting the name, another for the surname, one ImageView to show the picked photo picture, etc.
This will lead to one View interface, implemented by the Fragment. It will cooperate with one Presenter interface, implemented by another class.
Fine.
Now I have another feature: a screen for editing an existing person.
As it happens, the View for this feature is identical to the one for creating a new person. However, the Presenter is different. It will start by loading the existing person from db to pre-populate the view with the current data, and the action over the database when clicking "save" will be an update instead of a insertion.
So, I think this is an example of MVP where one View works with different implementations of the presenter to achieve different use cases.
Do you think this is a correct assumption, or do you think different features should have different View and Presenter interfaces?
Also, if you'd with a common View and different Presenters, will the implementation of the View be common, or would it lead to the same interface implemented by two classes? In practice, I see two options.
Having just one Fragment implementing the View. Depending on whether the user is about to create a new person or update an existing one, the Fragment should receive and use a different Presenter.
Having two Fragments. Each one would instantiate a different Presenter. Use composition or inheritance to avoid replication of code between the two fragments.
What do you think is better to do in these cases?
Thanks.
You'll run into this when you create a CRUD-like application using the MVP pattern on Android.
You can very easily just have the single view, as long as you document well in your class that it impl the 'view' for two different presenters, then it 'is okay'
I would personally suggest creating 2 views, one for 'create' and one for 'edit' (They might be the same(for now), but separating them makes it clear that they -are- different things.)
You could easily see a situation in the future (or another impl of this pattern) where your 'create' and 'edit' views actually have different APIs. Or slightly different visual cues, such as a button labelled 'create/add' in one and 'update' in another.
I'd personally make a view-library/helper class that both Views pull logic from. This should help you reduce overall LoC, even if you make 2 'view' classes. The benefit of this is that you change either the Create/Edit views easily without worrying about impacting the other. (I tend to think the 2 view files, would be easier to maintain down the road when there is even a 'slight' variance between Create/Edit)
This question already has answers here:
What is the benefit of using Fragments in Android, rather than Views?
(6 answers)
Closed 10 years ago.
What is the advantage to using Fragments over using custom Views that are reused in different layouts?
In the original blog post introducing fragments, Dianne Hackborn says that
[Fragments] make it easier for developers to write applications that can scale
across a variety of screen sizes, beyond the facilities already
available in the platform.
and she goes on to explain Fragments in the context of making a tablet layout for an app that combines the UI of two activities from the phone version of the same app.
But it seems that the same reuse could be achieved using custom Views. The main different between Fragments and Views seems to be that they have differing lifecycles...
The Fragment lifecycle is:
onAttach(), onCreate(), onCreateView(), onActivityCreated(), onStart(), onResume(), onPause(), onStop(), onDestroyView(), onDestroy(), onDetatch().
The View lifecycle is:
ctor, onFinishInflate(), onAttachedToWindow(), onMeasure(), onLayout(), onDetatchedFromWindow()
I'd like to hear from developers with experience writing large apps about what benefits (if any) they've seen in using Fragments vs custom Views to divide up the UI into reusable pieces.
The main reason is that fragments are more reusable than custom views.
Sometimes you can't create a fully encapsulated UI component relying on views alone. This is because there are things you would want to put into your view but can't because only an Activity can handle them, thus forcing tight coupling between an Activity and a View.
Here is one such example. Lets say you want to create a reusable UI component that, among many things, want to capture a photo and do something with it. Traditionally you would fire an intent that starts the camera and returns with the captured image.
Notice that your custom UI component can't fully encapsulate this functionality because it will have to rely on hosting Activity's startActivityForResult because views don't accept activity results (they can indirectly fire an intent through context).
Now if you wanted to reuse your custom UI component in different activities you would be repeating the code for Activity.startActivityForResult.
Fragment on the other hand cleanly solve this problem.
Similarly your fragment can contribute items to your options menu, something traditionally only an Activity could do. Again this could be important if the state of your custom view dictates what goes in the menu.
A fragment is way more than just a view. In fact it can even be totally without a view. It can have all sorts of stuff in it including AsyncTasks, various Listeners, file and database access and so on and so on.
Think of it as a small activity, but you can have multiple of them on the screen and work with them all including communicating with each other while they are visible.
E.g. you could have a list of shopping cart displayed in one fragment and the currently selected cart in detail in another fragment. You then e.g. change the quantity of an item in the detail view and the list view could be notified about it and update the total price in the list view. You can totally orchestrate interactions like that nicely while e.g. still having only one of them visible on a smaller screen device.
I have refactored a large business app (>15 activities) from activities to fragments to get good tablet support and I would never start a new app without fragments.
Update Feb 2016: While the above still holds true, there are complexities with fragments that caused many people to entirely avoid using them. Newer patterns such as usage of MVC approaches and more powerful views provide alternatives. As they say .. YMMV.
Some description:
Imagine Activity as a plate that hold one big cake.
Fragment would be a container that slices the same cake into pieces.
Each slice contains it own logics (listeners, etc).
And in total they are almost no different with the one big cake.
The benefit:
When you plate can't hold a big cake. (Screen is small) You can easily use a a few plates (Activity) to hold each of them WITHOUT the need to move your logics into the new activity.
Better re-usability. I have some instances where I could reuse a fragment entirely in another App. You might claim that a custom view could does that too. But refer to point 1, I could reuse it with just few lines of layout changes but for a custom view, it have to find a way to plug it into both layout and code.
It is, in some sense, a more OO ways of organising your UI logics in Android programming. When you have a feature (A new partition on the screen for example), you create a new Fragment class, with minor modification to existing activity class. However if you are programming only with activity, you will need to add logics and make big modification on tested class.
Just my 2 cents. :)
The lifecycle methods are probably your biggest hint. If you think about it, they correlate closely to the activity lifecycle (with some hooks into the activity and views). In fact, in the article you linked, Hackborn says:
In some ways you can think of a Fragment as a mini-Activity
As with many things in software design/development, there are a multitude of ways to do things. There are many different places you could put your code. Yes, you could probably put a lot into a view, but keeping different concerns separated in different classes is a good thing though. The classic pattern of this is MVC and it applies in this scenario. You don't want to bake in too much controller logic into your view. It's better to keep it in controller-like classes which are the activity and now the fragment. This is why the fragment's lifecycle is more like the activity's than the view's--it was made to facilitate this kind of organization.
I touched Fragments once and found them not very useful (see this post). From what I have read, A Fragment is really a fancy word for an Object with access to Activity Context. I like to ignore Fragments in my work, and just create these Objects myself. I have created very large, very demanding apps by passing an Activity to constructors, instead of Context. One major benefit, however, for using Fragments is that they are supported by the View layout system - so you can easily add them to Android xml (if you use it for your layouts).
Custom views are much more work than just using fragments in place of your activities. if you decide to use Activities and custom Views, you have to create your custom view, and then you have to implement the same activity lifecycle methods in your activity (a very similar lifecycle is used for fragments).
Using Fragments also allows you to separate components into their own classes (Fragments), rather than having too much logic in a single Activity. Let me ground that with an example:
Say you're implementing a magazine reader application. using fragments, you could create a fragment: ArticleList, which displays a list of articles, and another fragment: ArticleDisplay, which handles the logic for displaying content. you can then specify how these fragments should interact using the fragments tools, so that on a handset, you can use the full screen real-estate for ArticleDisplay, while on a tablet, you can display the fragments side by side.
If you were to attempt this with an Activity/custom view, you'd have the logic for both Fragments in your monolithic Activity, you'd have to write a custom view, and you'd have to debug this unwieldy monster.
Fragments are, in general, a more sophisticated and powerful way to write your applications. They can do everything an Activity can do, and more. If you don't need the extra functionality, the defaults will probably get you where you need to go, and with less work.
I know there have been quite a few questions about this, however, I'm still struggling to understand what role the Activity class should play when implementing the traditional Model-View-Controller design pattern on Android?
My gut feel is that it should be the Controller, however that means a one-to-one relationship between UI screens (since you must have one Activity per screen) and controllers, which defeats the point of MVC's loose coupling between the different components.
You are right. The xml interfaces could be defined as the View and your other class working with data as the Model.
The activity receive all the events and user inputs from the View ,so, we can easily said that it is the Controller.
But let's be clear , it's not a perfect (does it really exist ?) MVC
Have a look to this question , and more specifically , the first comment of the accepted answer, it may be useful
Activities can make competent controllers and, with fragments, you can also implement hierarchical MVC. Most of making MVC work is up to the programmer, because even in the strictest frameworks you can still find ways to do crazy things.
Android does not have a good architecture and it does not follow the MVC design pattern.
The best way to conceptualize Activity in MVC is as a View (with some controller logic) because it gets destroyed every time that a configuration change happens, such as a screen rotation or locale change, losing all its state.
The controller in this case would be the Application object, because it is your bridge to access the view (Activity and its GUI components) from code outside the Activity context. You have to use singletons so that there is only one Application object at a given time, otherwise there will be one Application object per process.
The Application object is not a good place to store the Model because its life cycle is detached from that of the Activities. It can get destroyed and recreated at any point of an Activity's life cycle (while the application is in the background) without causing it to restart, and then all its variables and references not assigned inside its onCreate() method will become null.
The Model therefore has to be stored on a GUI-less, headless fragment with setRetainInstance(true), that is linked to an activity, and has to be re-attached to it every time the activity is recreated. You have to use a fragment manager to ensure you are recovering the retained fragment and not creating it anew. This is also the best place to run background tasks, though you can also run them in the Application object. Never run tasks on an Activity as they will get destroyed on configuration changes.
I think the confusion may come in with defining a view as XML and so the Activity is mistaken for being the view. It's not. You pass the view (your XML layout) into the Activity which will then inflate the views contained within the XML layout. Your activity also passes data (models) into your views (EditText, TextView, extended version of base views, etc).
If you really want MVC then you can achieve this simply by setting up your view in an XML layout, create a view object which extends from your root view (if it's a RelativeLayout extend from that). From there you add your accessor methods and different logic needed for that view and you can then add unit testing around that.
In the Activity you will no longer pass in the ID of the layout and will instead do something like this:
CustomView customView = new CustomView(...);
setContentView(customView);
...
Of course almost all apps won't do this and you really don't need to do this. Calling findViewById is enough to link to that view object and call on the methods it has. Which in my mind, is MVC.