SmartLocation and its new API
I released the 3.x series of SmartLocation some time ago but I wanted to talk a bit about the API changes. I really wanted it to have a fluid API and be even easier to set up.
The 1.x series relied on some local broadcasting of intents, and the 2.x series used the same intents and wrapped them in a callback. It had some problems with a singleton retaining references, some receivers leaking and was very prone to be misused by users. Also the configuration was a mess, and it was proving to be a pain in the ass to add new features.
So I deleted everything and started from scratch.
I wanted it to be as simple as Picasso to set up. So I wrote down how I would like the API to be used first, and then wrote the code. Now it looks like this:
SmartLocation.with(context).location() .start(new OnLocationUpdatedListener() { ... });
I also wanted to be able to make it extensible. Every time Google Play Services are updated and its API changes, it's a pain and forces me to do the implementation. Now, even if I stopped doing stuff for the library or were on vacation (as it happened before), users could pretty much wrap the implementation of a new library in their own code, with the concept of providers. You can write your own provider if you want, or you could use one of the four shipped in the library:
- LocationBasedOnActivityProvider, which is the same strategy we had in the 2.x series, where we could use the activity recognition to change the parameters of location.
- LocationGooglePlayServicesProvider, which is the basic implementation of the Fused Location Provider, aka the location service shipped with Google Play Services.
- LocationManagerProvider, which is the old location stategy present since the beginning of times, using LocationManager.
- LocationGooglePlayServicesWithFallbackProvider, which wraps the Fused Location Provider and the LocationManager, and make it so if the first is not present, we would use the latter.
I've also added Activity Recognition as a standalone use case. Now users could request only the activity, without the location attached, by using the library too.
SmartLocation.with(context).activityRecognition() .start(new OnActivityUpdatedListener() { ... });
And I wanted to add new features, so Geofencing is now possible with the library, and without all the boilerplate that comes with Google's own examples.
Take a look at this example from the README file:
GeofenceModel mestalla = new GeofenceModel.Builder("id_mestalla") .setTransition(Geofence.GEOFENCE_TRANSITION_ENTER) .setLatitude(39.47453120000001) .setLongitude(-0.358065799999963) .setRadius(500) .build(); GeofenceModel cuenca = new GeofenceModel.Builder("id_cuenca") .setTransition(Geofence.GEOFENCE_TRANSITION_EXIT) .setLatitude(40.0703925) .setLongitude(-2.1374161999999615) .setRadius(2000) .build(); SmartLocation.with(context).geofencing() .add(mestalla) .add(cuenca) .remove("already_existing_geofence_id") .start(new OnGeofencingTransitionListener() { ... });
I am pretty happy with the result, and I've been using it for some projects I'm working on with success.
I also took the chance and added a couple of unit tests. I always wanted to have the green travis badge so here goes nothing.
Of course, there are a couple of settings that can be used to play around; you can always check out the sample project in the library for that.