• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Where should LocationManager be placed in MVP?

The logical place for that would be in the model, which contains the business logic, and database access components.

Thanks form your response!

Thats what I did at first time, the only problem I see is that the Model gets coupled with permissions API of Android SDK and you have to provide methods in all layers of the MVP to show and check permissions, isnt it? Any way to gently solve this?
 
Upvote 0
Sometimes a consequence of having a layered architecture, is the need for 'pass through' methods. But without seeing your code, I can't really say anything very specific. Can you provide some sample code to illustrate the problems you're having?

Yes of course, I don't have the code now at home but I will try to give you a specific example of the problem I'm facing with the MVP:

LocationManager requires to check location permissions just before calling the method (or supress warning with annotation), so the decision on where to put it in the MVP is not straightforward.

This code used to be in my Activity and worked fine having the Context and all the SDK Android imports available:

1. Inside onCreate() method of the Activity I ask for permissions:

Java:
private void checkPermissions() {
        Log.i(TAG, "ACCESS_FINE_LOCATION check");
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG, "ACCESS_FINE_LOCATION request");
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)) {
                showRequestPermission(REQUEST_CODE_LOCATION);
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        REQUEST_CODE_LOCATION);
            }
        } else {
            Log.i(TAG, "ACCESS_FINE_LOCATION granted");
        }
}

2. The callback returns the result of the permission check later:

Java:
@Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_LOCATION: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.i(TAG, "ACCESS_FINE_LOCATION granted");

                    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                            Log.i(TAG, "GPS provider enabled");
                        } else {
                            Log.i(TAG, "GPS provider disabled");
                        }

                        Log.i(TAG, "Listening to location updates...");
                        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
                    }
                } else {
                    Log.i(TAG, "ACCESS_FINE_LOCATION denied");
                }
                return;
            }
        }
    }

When triying to deocuple things with MVP architecture I decided leaving the permissions-related code in the Activity and moving LocationManager to the Model (is that even a good decision? what other choices are?):

Java:
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
           Log.i(TAG, "Listening to location updates...");
           locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, locationListener);
}

To avoid checking permissions in the Model I have to: 1) provide a pass-through methods in the Presenter so that the View can call the requestLocation() of the Model when the permission is granted and 2) either supress warnings (Annotation) or wrap with a try-catch in the requestLocation() call in the Model to avoid compilation error.

I have considered aadding pass-through methods to check permissions, moving permissions and LocationManager to the Presenter, encapsulate LocationManager with a Helper class and some others options, but none of them feel good to me. It ends up being everything coupled with Android SDK and / or with dirty interfaces for the VMP layers.

Java:
try {
           Log.i(TAG, "Listening to location updates...");
           locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, locationListener);
} catch (SecurityException se) {
           se.printStackTrace();
}

The decision on where to put the permissions-realated code, how to manage permissions in Presenter and Model and where to put the calls to Android SDK services or managers seems to be a bit arbitrary depending on which article / post you read. Also, some of them say that no Android SDK code or imports can be placed in Presenter or Model in the benefit of testability (or purity), but I find that the result is lots of boilerplate and pass-through methods.

To be honest, I have not been able to find two articles / posts that are consistent with the approach on how to handle these things in MVP and none of them cover the problem in detail ("it depends"). The Android Developers page does not give any guidance on this either... :-(

P.S. Thanks for your help and apologies for the long post! ;-)
 
Upvote 0
I'm not really surprised you haven't found much guidance on this, because I've looked for exactly the kind of information you require, and found it lacking. Basically, this isn't an exact science, and there are a multitude of different ways you can structure your code.
Rather than get hung up on patterns - and honestly, if you're tying yourself in knots trying to massage the code into a prescribed architectural pattern, then that leads me to question if it's the right approach.
I tend to apply some basic principles when I'm trying to come up with a software architecture:

- I try to write my code in such a way that it makes testing easy. Testing is a much neglected part of software development, and quite often it's not done properly.
- Program to the interface. Interfaces are a great way of decoupling your classes, and providing lots of flexibility in your design.
- Keep things cohesive. That means not mixing a lot of different functionality in the same class. If a class is called DBHelper, then it should only be concerned with database stuff.
- Aim for loose coupling - that is all about reducing the dependencies between classes. There's a great pattern that can help you with this, it's called 'Dependency Injection'.

But really, Android apps are heavily UI based, so a lot time your code revolves around Activities, and responding to user input. With the apps I've built, I didn't really feel the need to construct a complicated architecture.

When you say you moved the LocationManager to the 'model', what do you mean by that? What constitutes the 'model' in your application?
Maybe if you placed your code in a Github repo we could get some more context around the code fragments you've presented. Because it's a little difficult to visualise the full picture.

Note: I just saw your most recent post while writing this response. I'll have a look at the article.
 
  • Like
Reactions: twopelu
Upvote 0
Thanks again! Yes, I will try to share the code tomorrow so you can see the whole thing.

And many thanks for your useful advice also, I totally agree, I think I should be more pragmatic and less purist with this hehe.

I have a background (+10 years) in Java with similar architecture patterns, in those cases a simple MVC with DI fits perfectly.

But in this case with Android it all feels a bit akward hehe :-S
 
Upvote 0
When you say you moved the LocationManager to the 'model', what do you mean by that? What constitutes the 'model' in your application?

The Model in my app is only a class that stores some values in memory, such as the current location and a list of alerts, and encapsulates the calls to LocationManager. Here is where the coupling with Android SDK ocurrs. The Model has a reference to the Presenter to notify changes in data that have to be represented on the View (in my case, the Activity).
 
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones