I'm developing a small application that shows a list, and when an item is clicked it opens a secondary screen with the item details. I want to implement MVP as my architecture for this app, and i have been struggling figuring out how to do that when I have a single activity with 2 fragments.
Some questions came up as when an item from the list is clicked, a callback is sent to the first presenter, but at this point, who is in charge of opening the second fragment? do the presenters 'talk' to each other? should i do it through the activity?
Been looking around for examples of single activity with multiple fragments implementing MVP, but couldn't find something like that yet.
(Yes, it can be done otherwise, but the purpose of the app is to learn implementing MVP on a single activity with multiple fragments)
Appreciate any help!
Thanks!
After looking into different existing MVP sample projects I've decided to follow most of the concepts in the 'TODO-MVP-TABLET' git project by Google which can be found here:
https://github.com/googlesamples/android-architecture/tree/dev-todo-mvp-tablet
I've chosen this solution due to the level of abstraction and the ability to later on reuse any fragment in other activities without changing any code.
Solution principles:
Each fragment has a presenter defined by an interface.
There is a bigger presenter implementing all the smaller presenters.
The bigger presenter holds references to all of the smaller presenters and when a method is invoked it simply delegates the action to the relevant presenter.
Fragments are given the 'big' presenter as their presenter without actually being aware this is the case.
Smaller presenters should hold the reference to the view.
Diagram taken from Google's github page:
Update:
Link isn't valid, seems like Google removed the project from their samples. Will leave it in case they reupload it.
There are possibly many ways to implement MVP. Majorly we use 3 things.
- View
- Presenter
- Modal
you should be clear with your working of screen before creating these things.
eg if you want a login screen.
create structure (using interface) of activity first. like what your presenter and view will contain
eg.
public interface LoginPresenter {
void validateCredentials(String username, String password);
void onDestroy();
}
View structure:
public interface LoginView {
void showProgress();
void hideProgress();
void setUsernameError();
void setPasswordError();
void navigateToHome();
}
Now these are the classes you need to implement on your view class (Activity/fragment) and presenter where your logic part resides.
Now about your queries.
which means the activity will have both presenters instances.
No, your activity should not require to have multiple presenter. it already has opened fragment reference (by findfragmentby id or tag).
who is in charge of opening the second fragment?
you can open it from any of them either Activity/fragment.
if Activity use getfragmentsupportManager
if fragment use getfragmentManager
NOTE: For more info follow this git example.
https://github.com/antoniolg/androidmvp
Related
I am working on a small application using MVP pattern. My home activity has viewpager with multiple fragments in it and each fragment has its own presenter. Fragments aren't communicating with each other so the activity doesn't have any logic, it is just initializing fragments on start.
So if I would like to implement the pattern by the book and stay true to its principals should I implement presenter also for the activity? And if so what should be its role?
If you want to implement MVP by the book and stay true to its principals, every UI that has user interaction should have a presenter. In this case, if your activity is not interacting with the user, there is no need to have a presenter, and your fragments can have their own. If your activity needs, let's say show a loading to the user because of some data loading prior to show the fragments (this is a user interaction because you are interacting with the user to let them know that something is happening so they should wait), then might be good to consider having a presenter for the activity.
MVP doesn't care at all about whether is an Activity/Fragment/View, it just knows View which is considered as an abstraction of whatever can be shown to the user :)
That is at least, from the 'rules' perspective. My 2 cents is, be flexible, if you see that it actually ends up adding value to you and your project, do it, otherwise, sometimes you have to 'break' the rules or create your own.
For using the fragments with their own presenters, I try to use the presenter-contract classes duo to manage the UI events in the fragments.
For example, Consider a click event to show a toast message in case of two possible outcomes: 1. Save and 2. Delete
Then, I will declare two view contract methods like this:
interface View{
fun showSaveMessage()
fun showDeleteMessage()
}
And then, in the fragment, I will use an instance of my presenter class to display the messages at appropriate times like: presenter.doSaveAction(), the presenter in turn will cause the view to show the toast message.
Also, when I come to the actual logic of the fragment, like for fetching some data from a remote server, I use Interactor class along with the Presenter-View classes to perform it.
I believe staying true to all the principles is virtually dependent on what kind of application you are building. Sometimes, it is more feasible to use MVVM with MVP than only MVP pattern for the app architecture too.
I hope this answers your question, kind of?
I'm trying to use MVP in my new project. I have a Single Activity and multiple presenters that can be associated with it.
Presenter1 - Load Activity Data
Presenter2 - Load User data - that can be used in multiple Activities (So this presenter will be used in multiple activities
Presenter3 - User Actions - This can also be used in more than one Activities.
For now, I have used all the 3 presenters for one Activity. Is there anything I can do to use only single presenter to access all the methods for the 3 presenters? Searched a lot, but could not find any relevant reference. Thanks
I'm not sure it is the answer you're looking for but you could try an architecture more like clean architecture and isolate the logic of each of your use cases in an interactor and then inject your three interactors in one unic presenter for your activity.
And later, when you'll need to re-use that logic you will have a LoadUserInteractor and a UserActionInteractor to inject into that new presenter.
If you do not want to create interactors in your architecture you could create an abstract present who have the methods for load user data and user actions and let your activity presenter extends it with the load activity data but I'm not sure it will be long before it cause you some maintenance problems.
I was implementing MVP in my new application, then I came across a problem. I needed to call a method of View, inside View (Activity) itself. It is by definition of MVP code separation, wrong thing to do.
By definition:
The Presenter is in charge of the the orchestration between the Model and the View. It basically receive events from both and act consequently. The Presenter is the only component that knows others. It has a reference to the View and a another to the Model. (source)
In the same article it was mentioned that View does not reacts to user interactions, it passes control to Presenter to do the job. I have also read this SOF post about dependency rules.
In my case, I am using custom AppTheme. AppTheme needs to be set before setContent() call, what I am doing is create a method in View interface called setAppTheme() which my Activity implements, and there is code to apply theme. Now the problem is, this is called within the app, which makes calling of a View method inside its implementation.
To sum up, what my understanding of MVP either one of the following
should be true:
Do call View method inside Activity, because setTheme() wont work after setContent() and our presenter.setView() is in
onResume(), but will this satisfy MVP separation of M-V-P ?
Do not make interface method for setAppTheme(), instead create a private method in Activity which sets theme. This method will have
nothing to do with any layer of MVP. But question is, if project is
using MVP pattern, is this practice valid?
Here is my MVP:
public class AboutUsMVP
{
public interface Model
{
String getFbLink();
String getTwitterLink();
String getEmailLink();
String getCompanyLink();
}
public interface Presenter
{
void setView( View view );
void fbButtonClicked();
void twitterButtonClicked();
void emailButtonClicked();
void imageButtonClicked();
}
public interface View
{
void showFacebookPage();
void showTwitterPage();
void showEmailIntent();
void showCompanyWebsite();
void setAppTheme();
void setCustomActionBar();
}
}
Please do point out mistakes where I missed them.
From what I know, same case can be argued in the light of
setActionBar() and setOnClickListener() methods, although these
may require their separate post, but they are more relevant here and
new post for either of them will be duplicate.
Please note that my Activity implements View interface.
EDIT: More explanation
My View is actually Activity class. This is View of MVP, not Android API's View class. The thing is, there is a method setAppTheme() which only related to View of MVP, (Activity of Android). This call is not in the Contract (AboutUsMVP.java) which by Google convention should be AboutUsContract.java, this setAppTheme() is not in Contract, and it cant be, so does this violate MVP principle?
There is no possible alternative, one can say make an interface of setAppTheme(), if I do so, it will not work because:
setAppTheme() is called just after super() method, if not it is useless. And MVP's presenter starts working in onResume. If an interface is made, and setAppTheme() is brought into MVP's jurisdiction, it will have no effect.
Indeed, Views in an MVP are supposed to be dumb. This is: they don't contain any logic. Just receive the event generated by the user and immediately delegate its work to the presenter. The View can also inform the presenter that some events have happened (the view has been created, the screen rotate, etc)
This can lead to some confusions. Who is responsible of calling some methods? As you said the View has to perform some actions like setOnClickListener but the presenter is responsible of handling the event. Just have this in mind:
The View is just an interface. This means that you can use anything that implements that interface
Right now you're making a mobile app. But if you wanted to code a console or a desktop app, the presentation logic doesn't change. Anything that is specific to the "View technology" (android, desktop, etc) should be performed inside the code specific to that technology. This way your code will be loosely coupled to your tech stack
I believe #Pelocho answer is correct and you should mark it as the right one. But I would like to present my answer (that agrees with his) but from an alternative point-of-view. On for this different POV I would like to debate your on definition of presenter:
The Presenter is in charge of the the orchestration between the Model
and the View
So the question I propose here is: "what is this model that the presenter interacts with?". And my answer to it is to look into the classic "note-taking" application and argue that the model is text and associated meta-data, usually stored in some DB that the presenter will read, parse and push to the view.
Nowhere in this "model" the application theme is relevant. Theme is purely a function of the view. Theme is only associated to the final on-screen looks of it. Just like the view is the one in charge of layouting the content on screen, or to know what font size to use.
And that means even if those layouting, size, colors can be changed from a user settings option, it still falls outside the responsibility of the presenter and the model, as they're only interested in the content.
tl;dr:
Just read the theme on the Activity.onCreate (before super.onCreate) directly from the SharedPreferences and do not involve the Presenter on it.
The Android Developer Documentation states that one should avoid direct communication between fragments by implementing an interface. On further searching, the reason that I found for this is that it causes tight-coupling between the fragments. I'm having some difficulty understanding why it causes tight coupling and why that might be a problem.
Could someone show, by example code:
How direct communication between fragments would work.
Why this approach would be problematic
How using interfaces would solve the aforementioned problem.
Android fragments are often thought of as Views in MVP or MVC patterns, they should not contain any application logic within. All meaningful events from the fragment should be delegated to presenters which are often implemented via Activity.
Suppose you have a fragment A and a fragment B. Fragment A displays a list of items and fragment B displays details for the selected item. If you communicated fragments directly it would create a tight coupling between them since fragment A would need a concrete fragment B reference in order to instantiate it. If your application requirements change, for instance by showing fragment C instead of B, the tight coupling will pop out and you would have to deal with it. You can avoid this coupling by introducing a Presenter or Controller interface into your fragment. By calling this interface methods you can be sure that the implementation of your presenter logic is decoupled from fragment appearance logic.
For more information about developing decoupled application architecture check out this article http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/
Firstly, I know that with Model View Presenter there are different implementations, and in my mind as long as you have the layers of abstraction clearly defined and doing their appointed roles then how you implement this pattern is open to interpretation. I have been implementing this pattern in quite a few apps where there was just one Activity. I've now started a new project that has multiple Activities and attached Fragments, including nested fragments (ViewPager).
I'm now trying to translate the MVP to this project and I've hit a concept wall and would like some guidance and insights.
So far I've created the above structure and started to do a 1 : 1 relationship with View & Presenter (regardless of Activity or Fragment). I feel that this is OK, however if for example I sent a request to do something from an Activity View to its Presenter, which returns a result to the Activity View how would I go about propagating the result i.e. update all the other Activities/Fragments that are currently not in a Paused() or Stop() state. I feel like in this case there should be a central Presenter that updates all necessary Activity and Fragment Views, but I'm not sure how to go about doing this.
Currently when each Activity and Fragment is created it creates a new instance of a Presenter class, passing in itself as a reference (the Activities and Fragments implement their own interfaces), which the presenter stores as a WeakReference and can invoke the relevant interface methods when returning a result.
According to the docs whenever Fragments want to communicate with one another and the attached Activity you should use a callback interface. With this in mind should I have one callback interface that the Activity implements and the Fragments callback to whenever they request something, so in essence only the Activity would have a Presenter and Model layer that the Fragments have to callback to in order to make various requests?
Sorry if this sounds a bit muddled, hopefully this is clear enough to understand what I want to achieve, and if I’m thinking along the right lines... or totally off the mark!
I think this is okay to have a presenter inside activity. Basically activity is like a controller, it should know about the presenter.
It would be wrong to put a presenter inside a fragment if activity or other fragment needs it too. You can put a presenter inside a fragment only if this presenter is designed specifically for fragment.
which the presenter stores as a WeakReference and can invoke the relevant interface methods when returning a result
Why do you need a WeakReference here? If you have 1:1 relationship then I assume your presenter does not have it's own lifecycle, meaning that it's lifecycle depends on either activity or fragment. There is no risk of having memory leaks because it's not a singleton, right? It should be safe to have a strong reference.
I'm not sure if I answered your question because it looks a bit broad to me. My point is that, fragments are just separated "parts" of activity and you should treat them as parts. If presenter belongs to this part only, then it should be inside. Otherwise it should be in activity. You are right about using an interface to access activity, this is a well-known design approach which Google uses in their examples.
Nope, no interface anymore. You either use RxJava Observables to update all the views as described here or some kind of Bus(Otto-deprecated or EventBus). And you will like it because they make interacting too easy.