Android - context with MVP - android

I'm about creating a simple app with MVP implementation, and trying to make a permission request in a presenter. To make a permission request, I need to pass Context like this.
// Location permission has not been granted yet, request it.
ActivityCompat.requestPermissions(fragmentActivity, new String[]{permission}, requestId);
I've read several articles and they mention that using Context in a presenter is not a good exercise. So, I'm just wondering how people are handling a permission request with MVP. And I don't really know why using Context in a presenter is not good practice.
Please, help me to understand how I should handle a permission request and why using context is not good practice.
Thanks

You must never send any object related to Android to the presenter layer, and they must be fully decoupled.
to do these things I always remember a good sentence and that goes Do not inject objects, inject operations and behavior.
it so simple dont inject your context into your presenter which is a wrong practice. instead in your view contract (view interface) add a function called getPermission() then in your view implement that method along with other methods of your contract, then call that method whenever you need the permission.
thats the best way. trust me ;)

There are multiple flavors of MVP out there in practice. I am not here to start a debate which one is right and which one is wrong. As long as a particular flavor works for your scenario, it shall be used.
Instead, I will try to explain why the context in Presenter should be avoided and one of the ways I have avoided in my code.
One of the major reason you should not have a context in the presenter, there might be references to presenter which could leak the activity. In places where I had to deal with a context within the activity, I have accessed through Views.
interface View {
Context getContext();
}
interface Presenter {
void setView(View view);
}
So PresenterImpl implements a view, onCreate of the activity and resets it onDestroy of the activity. So the presenter never directly holds the context. But it holds the view, which has knowledge about the View.

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

Define MainActivity as static variable in order to access findViewById method

While I was coding, I wanted to use findViewById method to find a view that cant access in the current view but can be accessed via the MainActivity. So two options came to my mind. One is creating a static method from that object in the MainActivity class and access the static object. The second method is to create a static object form MainActivity class itself(this) and access the findViewById method by calling the static object. Please answer the method I should use.
And apart from that, it got me thinking that whether an Android developer should come across this type of scenario or whether I have done some improper coding to access findViewById method in MainActivity while I was in a different view.
You can take a look at the code in the below repo.
https://github.com/chrish2015/ExpenseTrackerLatest
Thanks
If you are inside a class that is neither a Context nor an Activity and you need to use a method which exists inside the activity or context, then simply pass the activity as a parameter to that class and take an instance to that activity inside your class.
public class MyAdapter extends ArrayAdapter { // this is not activity
private Activity mActivity; // activity is a member of this class.
public MyAdapter(Activity activity, List<String> data) {
mActivity = activity;
}
public View getView(...) {
// if you need to use findViewById:
View view = mActivity.findViewById(R.id.some_id);
}
}
Don't use any of your two methods.
I might be misunderstanding your first sentence, but just to be sure, are you asking for a way to access a View that exists in the MainActivity, while you're inside of a Fragment?
If that's what you're asking, then yes, as an Android Developer, there will definitely be moments where we come across this scenario. However, the solution is definitely NOT by making your Views or Context static.
This is one of the easiest ways to cause bugs to appear throughout your app, with a very high chance to cause memory leaks too. Here's an Article from Google talking about memory leaks related to keeping a reference to a Context: https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html
Rather than your two options, there are better solutions that developers typically use.
First of all, keep in mind that you should NOT be directly accessing any Views from outside of your current layout... meaning, that if you're in a second Activity, you don't directly access Views from the first Activity, or if you're in a Fragment, you don't directly access Views that belong to it's FragmentActivity.
Instead, you let the Activity or Fragment handle it's own Views.
So for example, if you're in another Activity and you want to update some data in the previous Activity, you can take advantage of an Activity's startActivityForResult() and onActivityResult() to obtain the data necessary to update the Activity immediately upon returning to the app.
For Fragments, there's actually a tutorial from the Android Documentation that describes a very good way to communicate between other Fragments: https://developer.android.com/training/basics/fragments/communicating
This method is to use interfaces as a callbacks, so another Fragment or the Activity will be able to receive data and update it's Views within it's own layout.
So for your case, if you're using Fragments and an Activity, you can easily have your fragments and activities communicate to each other in a safer and more reliable way.
Also, make sure you read up more on static and it's effects on your code, especially the side effects on Android components. Do not carelessly use static without considering some of the effects it might cause, because that would cause an endless amount of trouble to your code.

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

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.

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.

can Dagger be used to perform injection on a Content Provider?

I have recently been integrating Dagger into a project that uses ContentProviders. I create a single ObjectGraph instance in my custom Application object, and basically in each managed component:
Activity,
Fragment,
Service
... Then, I call getApplication(), downcast to my custom Application object, and force the injection through some custom implementation in my Application class. This seems to be the prescribed method of performing injection based on the samples I've seen posted by the guys at Square.
This pattern doesn't hold for ContentProvider instances though as their lifecycle isn't as predictably tied to the lifecycle of the Application object, ie ContentProviders can be, and as I'm observing frequently are, created before the Application object is created (for reasons I have yet to comprehend).
so... does anyone have a nice way of injecting ContentProviders using Dagger? I've so far made it by having an isInjected() call at the beginning of each of my ContentProvider's interface methods (insert, query, update, delete)... basically a hacky form of lazy initialization. But this seems far from ideal. Is there a more prescribed approach to injecting ContentProviders?
The Application subclass is just a convention since it's usually the first object created. Our apps do not have content providers which is why we use them. There's nothing that says you can't put it somewhere else.
You can just use the traditional singleton pattern for instantiating and holding a reference to the ObjectGraph.
public final class Dagger {
static ObjectGraph og;
static ObjectGraph og() {
if (og == null) {
og = ObjectGraph.create(..);
}
return og;
}
}
The first person to access will initialize the instance which will be used for the lifetime of the process.
If your content provider is in a different process than your main application this solution will still work. Or you could simply create the graph when your content provider is created since it will be the only consumer. Normal multi-process rules still apply, of course, so no instances will be shared with the other processes.

Categories

Resources