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! ;-)