I am working on an app that should get accurate user location continuously if user is inside a specific zone. The location updates should be saved on a server (Parse.com) so other users can get the current location of the user.
The flow is:
- Application onCreate -->
- start Service with LocationListener -->
- onLocationChanged -->
- save new location on Parse.com -->
- Parse.com Cloud afterSave method send push notification to users -->
- other users get notifications via broadcast reciever -->
- update user marker on map <--
Questions:
I am not sure about how to implement step 4, should I save the new location on parse inside the onLocationChanged method? should I pass it to a BroadcastReciever and save it on parse there? or should I pass it to a static method in my CurrentUser class that will perform the save on server?
I have noticed the requestLocationUpdates documentation says:
"This method is suited for the foreground use cases, more specifically for requesting locations while being connected to LocationClient. For background use cases, the PendingIntent version of the method is recommended."
In my case, which method should I use?
What values should I use for getting almost real time location without consuming more than 5% of battery power per hour?
My Service Class:
public class UserTracker extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener, LocationListener{
static int GEOFENCE_STATUS;
final static int INSIDE_GEOFENCE = 9001, OUTSIDE_GEOFENCE = 9002;
static final int MINIMUM_ACCURACY = 26;
final static int GEOFENCE_RADIUS = 2000;
static final int NULL_LOCATION_ERROR = 7001;
static final int INSIDE_INTERVAL = 10000, INSIDE_FASTEST_INTERVAL = 1000, INSIDE_SMALLEST_DISPLACEMENT = 10;
static final int OUTSIDE_INTERVAL = 300000, OUTSIDE_FASTEST_INTERVAL = 60000, OUTSIDE_SMALLEST_DISPLACEMENT = 100;
static Location eventLocation;
LocationClient lc;
@Override
public void onCreate() {
super.onCreate();
eventLocation = new Location("Test");
lc = new LocationClient(getApplicationContext(), this, this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
double eventLat = intent.getDoubleExtra("Latitude", -1);
double eventLon = intent.getDoubleExtra("Longitude", -1);
if (eventLat == -1 || eventLon == -1) {
stopSelf();
return START_REDELIVER_INTENT;
}
eventLocation.setLatitude(eventLat);
eventLocation.setLongitude(eventLon);
lc.connect();
return START_STICKY;
}
public int getGeofenceStatus(Location currentLocation) {
if (currentLocation == null) {
return NULL_LOCATION_ERROR;
}
if (currentLocation.distanceTo(eventLocation) > GEOFENCE_RADIUS) {
Log.d(TAG, "User is outside geofence");
return OUTSIDE_GEOFENCE;
} else {
Log.d(TAG, "User is inside geofence");
return INSIDE_GEOFENCE;
}
}
public void requestLocationUpdates(int status) {
GEOFENCE_STATUS = status;
LocationRequest request = LocationRequest.create();
switch (status) {
case NULL_LOCATION_ERROR:
stopSelf();
break;
case INSIDE_GEOFENCE:
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
request.setInterval(INSIDE_INTERVAL);
request.setFastestInterval(INSIDE_FASTEST_INTERVAL);
request.setSmallestDisplacement(INSIDE_SMALLEST_DISPLACEMENT);
break;
case OUTSIDE_GEOFENCE:
request.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
request.setInterval(OUTSIDE_INTERVAL);
request.setFastestInterval(OUTSIDE_FASTEST_INTERVAL);
request.setSmallestDisplacement(OUTSIDE_SMALLEST_DISPLACEMENT);
break;
}
lc.requestLocationUpdates(request, this);
}
@Override
public void onLocationChanged(Location location) {
int newStatus = getGeofenceStatus(location);
int accuracy = (int) location.getAccuracy();
String message = "Geofence status: " + newStatus +
"\nAccuracy: " + accuracy +
"\nDistance to event: " + location.distanceTo(eventLocation);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (newStatus == INSIDE_GEOFENCE && accuracy < MINIMUM_ACCURACY) {
Log.d(TAG, "Accuracy is good");
// do the save on server procees
}
if (GEOFENCE_STATUS != newStatus) {
requestLocationUpdates(newStatus);
}
}
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.d(TAG, "LocationClient connection failed: " + result.getErrorCode());
}
@Override
public void onConnected(Bundle arg0) {
Location currentLocation = lc.getLastLocation();
requestLocationUpdates(getGeofenceStatus(currentLocation));
}
@Override
public void onDisconnected() {
Log.d(TAG, "LocationClient disconnected");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}