Reputation: 51
I'm trying to learn MVVM, and I faced some issue which I don't know how to resolve. I wanted to make a repository which will get user coordinates in background thread. The thing is in order to make it work, I have to pass context for it, but I don't know how to pass context for repository. I can't just pass it that easily like in some activity class.
Repository
public class LocationRepository {
private void test() {
FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(CONTEXT);
{
if (ContextCompat.checkSelfPermission(CONTEXT, Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(CONTEXT, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(CONTEXT, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
client.getLastLocation().addOnSuccessListener(CONTEXT, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location != null){
//TODO
}
}
});
}
else{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{
Manifest.permission.INTERNET, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION
}, 1);
}
}
}
}
}
Upvotes: 2
Views: 1900
Reputation: 2680
Consider this if you do not wanna use Dependency Injection.
This is a minimal example leaving lots of stuff open for improvements!
In this example we not gonna pass down the Context
as this can lead to memory leaks (if not thoroughly handled) but creating the FusedLocationProviderClient
in the Activity and passing it to the ViewModel and the Repository.
Note: Avoid passing Android related things like Context
, View
's etc down to your ViewModel and lower layers. It will make testing and refactorings easier, because you less depend on Android.
In your Activity you get your ViewModel and you create your FusedLocationProviderClient
:
public class YourActivity : Activity() {
private FusedLocationProviderClient locationProvider = LocationServices.getFusedLocationProviderClient(this.applicationContext);
// Either you pass FusedLocationProviderClient via constructor to the ViewModel, or via a setter later
private YourViewModel viewModel = // ...
override void onCreate() {
super.onCreate();
// if you wanna set the locationProvider via setter
viewModel.setLocationProvider(locationProvider); // this should not leak when the activity finishes as there is no reference to the Activity or its view
}
}
Then in your ViewModel you either get the locationProvider
via Constructor or a setter:
public class YourViewModel extends ViewModel {
// You can either create a new LocationRepository in the viewModel,
// or you can pass an instance via Constructor (which I recommend for better testability)
// or you pass it via a setter
private LocationRepository locationRepository;
public YourViewModel(FusedLocationProviderClient locationProvider) {
locationRepository = new LocationRepository(locationProvider);
}
// alternatively using a setter
public void setFusedLocationProviderClient(FusedLocationProviderClient locationProvider) {
locationRepository = new LocationRepository(locationProvider);
}
// this function calls your repository
public void foo() {
// ensure LocationRepository is initialized or you will get a Nullpointer here,
// or check if (locationRepository != null) { ... } before accessing it
localRepository.test()
}
@Override
public void onCleared() {
// do cleanup
// stop ongoing work (in your repository)
// unregister listeners (in your repository)
}
}
public class LocationRepository {
private FusedLocationProviderClient locationProvider;
public LocationRepository(FusedLocationProviderClient locationProvider) {
this.locationProvider = locationProvider;
}
public void test() {
// ... now you can use FusedLocationProviderClient (without the need of having a context
}
Upvotes: 3