Android MVP - Calling View method inside View implementation (Fragements or Activity) - android

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.

Related

Android MVP: Handling all exceptions inside a presenter class

I'm implementing an android application in MVP architecture.
I keep a reference to view inside my presenter and do time-consuming tasks such as loading from network inside my model.
My problem is that in each call inside my presenter which I want to call a method of View, it may happen that view is destroyed already and its reference is set to null inside presenter.
So when I received results from model, before each call like mView.updateUISomehow() in need to add if (mView!=null) since when control reaches to this point it may happen that mView is null.
I want to know are there any methods that I skip all null checking and handle all possible exception of presenter class in a class-wide exception handler.
P.S. I know about MVVM, LiveData and Room. I want to resolve this exact problem :)
BasePresenter<View>{
View view
updateUI(){
if(view != null)
callUI()
}
abstract callUI();
}
Your controller would have the knowledge of updateUI(), you may choose how to handle that
YourPresenter<ThatElusiveview> extends BasePresenter<ThatElusiveEview>{
callUI(){
// hoping this is not directly called from the controller!!
}
}
I faced the same problem when I was using MVP with too many UI update calls which will happen in the real scenarios. Well did the refactor to Jet pack. I understand your dilemma.
I believe it is doable if you provide Presenter with listener to view, so if view gets destroyed, Presenter will hold the communication from the controller toward View.
it does sound like checking the view != null, but you can have enumerations of different type of updates going from presenter to View. which you can put in one place to check and then direct them to respective update method depending on the type of enumeration action.
This will also help reading the code regarding different action that presenter is capable of sending to the View

MVP design pattern practical observations

I am trying to understand MVP design pattern practically and went through this link and few other links and made some observation. I want to know that all the below observations are correct for implementing MVP design pattern practically?
Activity, Fragments and our xml layouts will be part of View.
Our POJO classes or the classes which are responsible for fetching data, making API calls or calling Web services are part of Model.
We create an interface which contains abstract methods for various events we need to perform on View or various events for the lifecycle of view. Activity/Fragment will implement that interface and pass its reference to Presenter constructor.
Presenter will have reference to both View and Model. Its constructor will contain reference to an interface which Activity implemented and it will create an object of Model.
Whenever an action is performed on View or for any lifecycle callback of View, a method of Presenter is called from View. That method will interact with both Model and View as per requirement. It will call method of Model and will call the method of interface that Activity implemented so both Model and View can perform action in their classes.
Your understanding is mostly correct:
Correct.
Quite correct. Although note that in MVP design pattern terminology the notion Model (M) is pretty general. In practice Model is divided in a few layers depending on their "functionality", e.g. Interactor, Repository, network etc.
In general, correct.
Correct regarding the VP part and incorrect on "it will create an object of Model". Presenter should not create an instance of Model, it should communicate with it via an interface too.
In general, correct. However, View should not care about lifecycle of View. Model should provide data.

Implementing MVP on a single activity with two (or multiple) fragments

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

Should the Observing/Subscribing be done on the View or Presenter?

For example if there's an activity with a button(View). When this is pressed, it calls a Presenter method, this method gets an observable from a service(Model) - which could take a long time to reply with results.
Should the subscriber for these results be kept on the Presenter? Then depending on the results, the Presenter would call the relevant View's actions?
Or should the subscriber be on the View? As I've been seeing in these other rx android example projects. In which case the activity/fragment would be calling other View or Presenter methods depending on the subscription's results.
The main goal of MVP pattern is to decouple the data access mechanism from view(activities, fragments). To make an application to be easily extensible and maintainable we need to define well separated layers.
If you return you subscriber on the view then it will break the MVP pattern. You should make your view as dumb as possible. So you should subscribe on presenter layer and let the presenter layer decide what should be the next step in the view. There might be some situation arise when different kinds of action might happen on the view. That logic should not be present on view.
**NB:This is just a suggestion. Make your view dumb. But you have to decide how much dumb you will make the view based on the action it performs. For an example there is a button whose click event pop up a yes/no kind of dialog. You should not call the presenter that the button clicked and let it tell the view to open a dialog.
But the situation you describe above you should use a presenter layer.
Presenter should do all the logic and heavy lifting while view is simple as possible. It only registers user input and, after all is done, shows the results.
Should the subscriber for these results be kept on the Presenter? Then
depending on the results, the Presenter would call the relevant View's
actions?
Yes, this is correct way to do it.
I would suggest to always keep subscription on Presenter. If View is allowed to 'see' the Model, it should only interact with Model in some simple manner such as data binding and simple validation. Otherwise, View is dump, Presenter proceeds all business logic.
Passive View and Supervising Controller are two variants of MVP for your references.
Please also checkout a new MVP framework for Android at http://robo-creative.github.io/mvp. Samples on there explains the difference between those variants. Have fun!

Multiple Activities / Fragments and the Model View Presenter pattern

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.

Categories

Resources