Android — Retrieving Google Location using RxJava and Clean Architecture
Working with Google location is not exactly a simple task, but the FusedLocationProvider API helps and simplifies a lot for us.
In this post, I’m going to cover an approach I implemented to retrieve data from Google Location services and show it to the user through a clean architecture project.
Since we’re following clean architecture, let’s start with our architecture and explain how will it work.
Instead of spending time here explaining the clean architecture concept, I’m going to assume you are already familiarized with that and explain how it works on our scenario.
If you do not know how clean architecture works, you could have a look at this nice post about it:
Domain Layer: The domain layer will take care of the use case (GetLocationUseCase) that will consume the LocationRepository data.
This layer will only be implemented by other layers.
Data layer: This layer will be responsible for requesting the Google location data itself by using the Fused Location Provider API (https://developers.google.com/location-context/fused-location-provider), it will be encapsulated inside the GoogleLocationDataSource class.
This layer will implement the domain layer.
App Layer: Furthermore, we will need to define a bridge from the business logic (Domain) to the UI (Application), which will be handled by the use case injected inside our TrackerViewModel.
This layer will implement both layers (Data and Domain) in order to provide the dependency injection we need.
Without further ado, let’s check how it will be from the code side, starting by the GoogleLocationDataSource class
First, we set up the Google Location API by defining the FusedLocationProviderClient, LocationRequest, and the LocationCallback.
FusedLocationProviderClient: Will take care of requesting the location updates using the requestLocationUpdates function and the lastLocation through a listener.
PS1: It will allow us to remove the location updates callback also (removeLocationUpdates function).
LocationRequest: Defines the necessary quality of service parameters that will be used by our location provider client, such as interval and priority, you could find more info here: https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html
LocationCallback: It’s pretty straight forward, it will be the callback that will receive the locations data provided by Google Location.
LocationSubject: This variable will be in charge of posting the result we receive on LocationCallback and will be exposed as a Flowable to the repository.
LocationObservable: That’s the bridge that we will define between our data source and the repository. Note that we associated the location request functions to the flowable using the doOnSubscribe to start requesting location updates and doOnCancel to stop requesting location updates.
LocationEntity: It is the object that wraps the latitude and longitude of the location, which should only be accessed from the data layer.
The location repository interface will be defined on the domain layer to be used as a protocol by the use case.
And the repository implementation will be the actual implementation of the repository defined on the data layer and will be created with an injected instance of our GoogleLocationDataSource already defined. It must map to a domain layer object (LocationDomainModel) since the domain layer is not aware of the data layer and doesn’t have access to the LocationEntity.
The use case will inject the repository interface we defined to be used by our view model.
In our view model, whenever we have granted permission to the location, we use the injected use case to observe the location data, we must map the result to our UI model and post the value using the _locationModel livedata.
PS: The baseSubscribe is a function defined on my BaseViewModel, it will be available on my Github repo.
And finally, we have our fragment that will handle the Google Maps interface and the location permission. To receive the location data, the only thing we need to do is to observe the locationModel observable.
PS: The location was changed using the emulator location feature.
The Fused Location API is pretty simple and straightforward, but we must define a proper way to request this data, and using a clean architecture approach could help us on this task by making it more robust and organized.
For more details, please, check my Github project with this implementation: