I Want To Post Location Updates Every 15mins To Server Even When The App Is Not Running In The Foreground
Solution 1:
Updated answer
Old answer will not work for apps targeting M or higher, because static connectivity receiver will no longer receive broadcasts.
Now, the best option is a FusedLocationApi
, which is a part of Google Play Services.
compile'com.google.android.gms:play-services-location:[version_here]'
Create an IntentService handling location updates
/**
* Handles location updates from FusedLocationProvider
*/publicfinalclassLocationUpdateServiceextendsIntentService {
privatestaticfinalStringTAG="LocationUpdateService";
publicstaticfinalStringACTION_HANDLE_LOCATION="ACTION_HANDLE_LOCATION";
publicLocationUpdateService() {
super(TAG);
}
@OverrideprotectedvoidonHandleIntent(final Intent intent) {
if (intent != null) {
finalStringaction= intent.getAction();
if (action != null) {
switch (action) {
case ACTION_HANDLE_LOCATION:
onActionHandleLocation(intent);
break;
default:
Log.w(TAG, "onHandleIntent(), unhandled action: " + action);
break;
}
}
}
}
privatevoidonActionHandleLocation(@NonNullfinal Intent intent) {
if (!LocationResult.hasResult(intent)) {
Log.w(TAG, "No location result in supplied intent");
return;
}
finalLocationResultlocationResult= LocationResult.extractResult(intent);
if (locationResult == null) {
Log.w(TAG, "LocationResult is null in supplied intent");
return;
}
// TODO send to server using a blocking request.// Remember that this is the background thread already
}
}
Don't forget to add it to Manifest application tag
<serviceandroid:name=".LocationUpdateService"/>
Request location permission, connect GoogleApiClient, and you now may do the following
@NonNullprivatestatic PendingIntent createLocationServiceIntent(@NonNullfinal Context context) {
finalIntentintent=newIntent(context, LocationUpdateService.class);
intent.setAction(LocationUpdateService.ACTION_HANDLE_LOCATION);
return PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
publicstaticvoidscheduleLocationUpdates(@NonNullfinal Context context,
@NonNullfinal GoogleApiClient googleApiClient) {
// Make sure you have permission, request if necessaryif (googleApiClient.isConnected() &&
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
// ACCESS_COARSE_LOCATION, depending on what you want
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient,
LocationRequest.create().setInterval(AlarmManager.INTERVAL_FIFTEEN_MINUTES),
createLocationServiceIntent(context));
}
}
publicstaticvoidunscheduleLocationUpdates(@NonNullfinal Context context,
@NonNullfinal GoogleApiClient googleApiClient) {
if (googleApiClient.isConnected()) {
LocationServices.FusedLocationApi
.removeLocationUpdates(googleApiClient, createLocationServiceIntent(context));
}
}
Old answer
AsyncTask is intended for short background operations, mostly when you are waiting in UI. You should better start a Service with WakeLock in this case. But be aware that you will likely drain a battery doing so every 15 minutes. Consider not scheduling Alarms when device is not connected to network.
1) Register a static BroadcastReceiverin Manifest to monitor if device is connected. Intent action for network events in android sdk
2) When device gets connected to the internet and locations are allowed, start a Service that will hold WakeLock, listen for one location update, unregisters location updates, sends location to server, schedules AlarmManager, releases WakeLock and cals stopSelf(); Consider a timeout if location updates are not comming. If timeout reached, unregister location updates, register next Alarm, release WakeLock and call stopSelf.
3) If you receive network disconnected in a Receiver, cancel all Alarms and stop Service if running.
Code sample for step 2 as requested
publicfinalclassConnectivityReceiverextendsBroadcastReceiver {
@OverridepublicvoidonReceive(Context context, Intent intent) {
finalAlarmManageralarmManager= (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
finalPendingIntentwakeupIntent= PendingIntent.getService(context, 0,
newIntent(context, LocationUpdaterService.class), PendingIntent.FLAG_UPDATE_CURRENT);
finalbooleanhasNetwork= !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (hasNetwork) {
// start service now for doing once
context.startService(newIntent(context, LocationUpdaterService.class));
// schedule service for every 15 minutes
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_FIFTEEN_MINUTES,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, wakeupIntent);
} else {
alarmManager.cancel(wakeupIntent);
}
}
}
publicfinalclassLocationUpdaterServiceextendsServiceimplementsLocationListener {
privateenumState {
IDLE, WORKING;
}
privatestatic State state;
private LocationManager locationManager;
private WakeLock wakeLock;
static {
state = State.IDLE;
}
@OverridepublicvoidonCreate() {
super.onCreate();
finalPowerManagerpm= (PowerManager) getSystemService(Context.POWER_SERVICE);
this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "LocationUpdaterService");
}
@Overridepublic IBinder onBind(Intent arg0) {
returnnull;
}
@OverridepublicintonStartCommand(Intent intent, int flags, int startId) {
if (state == State.IDLE) {
state = State.WORKING;
this.wakeLock.acquire();
// register location updates, not gonna code it you know
}
return START_STICKY;
}
@OverridepublicvoidonDestroy() {
super.onDestroy();
state = State.IDLE;
if (this.wakeLock.isHeld()) {
this.wakeLock.release();
}
}
privatevoidsendToServer(Location location) {
// send to server in background thread. you might want to start AsyncTask here
}
privatevoidonSendingFinished() {
// call this after sending finished to stop the servicethis.stopSelf(); //stopSelf will call onDestroy and the WakeLock releases.//Be sure to call this after everything is done (handle exceptions and other stuff) so you release a wakeLock//or you will end up draining battery like hell
}
@OverridepublicvoidonLocationChanged(Location location) {
locationManager.removeUpdates(this); // you will want to listen for updates only once
sendToServer(location);
}
@OverridepublicvoidonProviderDisabled(String provider) {
}
@OverridepublicvoidonProviderEnabled(String provider) {
}
@OverridepublicvoidonStatusChanged(String provider, int status, Bundle extras) {
}
}
Solution 2:
Yes you can schedule alarms for a receiver every 15 mins and trigger a service which can start an AsyncTask and post the location update
Post a Comment for "I Want To Post Location Updates Every 15mins To Server Even When The App Is Not Running In The Foreground"