Skip to content Skip to sidebar Skip to footer

I Want To Post Location Updates Every 15mins To Server Even When The App Is Not Running In The Foreground

I want the location updates to be sent to the server every 15mins to time interval from android phone to the server.Is the service or the alarm manager is the best option. If i sta

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"