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 start a service,can i start an asynctask to post locations to the server.?
here is the code i used :
@Override
public void onStart(Intent intent, int startId) {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
listener = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 4000, 0, listener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
4000, 0, listener);
}
public class MyLocationListener implements LocationListener {
public void onLocationChanged(final Location loc) {
Log.i("**************************************", "Location changed");
if (isBetterLocation(loc, previousBestLocation)) {
loc.getLatitude();
loc.getLongitude();
//
// intent.putExtra("Latitude", loc.getLatitude());
// intent.putExtra("Longitude", loc.getLongitude());
// intent.putExtra("Provider", loc.getProvider());
//
// sendBroadcast(intent);
}
}
public void onProviderDisabled(String provider) {
Toast.makeText(getApplicationContext(), "Gps Disabled",
Toast.LENGTH_SHORT).show();
}
public void onProviderEnabled(String provider) {
Toast.makeText(getApplicationContext(), "Gps Enabled",
Toast.LENGTH_SHORT).show();
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
}
I dont know how to run the service background every fifteen minutes of interval.. I want to start an aysnctask when i get fresh location updates.Is the service or the alarm manager is the best option. If i start a service,can i start an asynctask to post locations to the server.?
Permissions. In order to receive location updates from a NETWORK_PROVIDER or GPS_PROVIDER , you must request the user's permission by declaring either the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission, respectively, in your Android manifest file.
Using the fused location provider API, your app can request the last known location of the user's device.
Settings > Location > Mode > Battery Saving . This mode only uses WiFi, Bluetooth or mobile data instead of GPS to determine the user location. That's why you have to check if the network provider is enabled and locationManager. isProviderEnabled(LocationManager.
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
*/
public final class LocationUpdateService extends IntentService {
private static final String TAG = "LocationUpdateService";
public static final String ACTION_HANDLE_LOCATION = "ACTION_HANDLE_LOCATION";
public LocationUpdateService() {
super(TAG);
}
@Override
protected void onHandleIntent(final Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (action != null) {
switch (action) {
case ACTION_HANDLE_LOCATION:
onActionHandleLocation(intent);
break;
default:
Log.w(TAG, "onHandleIntent(), unhandled action: " + action);
break;
}
}
}
}
private void onActionHandleLocation(@NonNull final Intent intent) {
if (!LocationResult.hasResult(intent)) {
Log.w(TAG, "No location result in supplied intent");
return;
}
final LocationResult locationResult = 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
<service android:name=".LocationUpdateService"/>
Request location permission, connect GoogleApiClient, and you now may do the following
@NonNull
private static PendingIntent createLocationServiceIntent(@NonNull final Context context) {
final Intent intent = new Intent(context, LocationUpdateService.class);
intent.setAction(LocationUpdateService.ACTION_HANDLE_LOCATION);
return PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void scheduleLocationUpdates(@NonNull final Context context,
@NonNull final GoogleApiClient googleApiClient) {
// Make sure you have permission, request if necessary
if (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));
}
}
public static void unscheduleLocationUpdates(@NonNull final Context context,
@NonNull final 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 BroadcastReceiver in 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
public final class ConnectivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final PendingIntent wakeupIntent = PendingIntent.getService(context, 0,
new Intent(context, LocationUpdaterService.class), PendingIntent.FLAG_UPDATE_CURRENT);
final boolean hasNetwork = !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (hasNetwork) {
// start service now for doing once
context.startService(new Intent(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);
}
}
}
public final class LocationUpdaterService extends Service implements LocationListener {
private enum State {
IDLE, WORKING;
}
private static State state;
private LocationManager locationManager;
private WakeLock wakeLock;
static {
state = State.IDLE;
}
@Override
public void onCreate() {
super.onCreate();
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "LocationUpdaterService");
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(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;
}
@Override
public void onDestroy() {
super.onDestroy();
state = State.IDLE;
if (this.wakeLock.isHeld()) {
this.wakeLock.release();
}
}
private void sendToServer(Location location) {
// send to server in background thread. you might want to start AsyncTask here
}
private void onSendingFinished() {
// call this after sending finished to stop the service
this.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
}
@Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this); // you will want to listen for updates only once
sendToServer(location);
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With