Background Service with Location Listener in Android

Background service with location listener in android

First you need to create a Service. In that Service, create a class extending LocationListener. For this, use the following code snippet of Service:

public class LocationService extends Service {
public static final String BROADCAST_ACTION = "Hello World";
private static final int TWO_MINUTES = 1000 * 60 * 2;
public LocationManager locationManager;
public MyLocationListener listener;
public Location previousBestLocation = null;

Intent intent;
int counter = 0;

@Override
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
}

@Override
public void onStart(Intent intent, int startId) {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
listener = new MyLocationListener();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 4000, 0, (LocationListener) listener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 4000, 0, listener);
}

@Override
public IBinder onBind(Intent intent)
{
return null;
}

protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}

// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;

// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}

// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;

// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());

// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}



/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}



@Override
public void onDestroy() {
// handler.removeCallbacks(sendUpdatesToUI);
super.onDestroy();
Log.v("STOP_SERVICE", "DONE");
locationManager.removeUpdates(listener);
}

public static Thread performOnBackgroundThread(final Runnable runnable) {
final Thread t = new Thread() {
@Override
public void run() {
try {
runnable.run();
} finally {

}
}
};
t.start();
return t;
}
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);

}
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

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();
}
}

Add this Service any where in your project, the way you want! :)

Background service in android 10 to get location in every 10 minutes

Due to the android's limitations for background tasks in post-O devices, background services are destroyed by the android system if the app is in the background for some time.
You should use startForeground() in onStartCommand() to start the service as a foreground service and also show the notification for the same.

OnLocationChanged() Doesn't work in background

Currently you are using a background service. It works when is running as and as soon as app goes in background, service stops.

To get continuous updated in background you need to update service to a foreground service.

ForegroundService.java

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
//stopSelf();
return START_NOT_STICKY;
}

AndroidManifest.xml

 <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

MainActivity.java

public void startService() {
Intent serviceIntent = new Intent(this, ForegroundService.class);
serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android");
ContextCompat.startForegroundService(this, serviceIntent);
}

If you are running the app on android 10 and above you need to request Background location.

  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

You can read all about background location, it limitation and foreground service here - https://developer.android.com/about/versions/oreo/android-8.0-changes

https://developer.android.com/guide/components/services

Background service when app is not open or closed


According to google developer recent policy you shouldnt be using
manifest based broadcast receivers , though it will not work above 26
SDK

https://developer.android.com/guide/components/broadcasts#changes-system-broadcasts

So no need to use broadcast receiver to restart service.

Use this code to restart service

Updated service class

public class LocationService extends Service {
private static final String TAG = "SERVICE";
private LocationManager mLocationManager = null;
private static final int LOCATION_INTERVAL = 0;
private static final float LOCATION_DISTANCE = 0;

private class LocationListener implements android.location.LocationListener {
Location mLastLocation;

public LocationListener(String provider) {
Log.e(TAG, "LocationListener " + provider);
mLastLocation = new Location(provider);
}


@Override
public void onLocationChanged(Location location) {

mLastLocation.set(location);
}

@Override
public void onProviderDisabled(String provider) {
Log.e(TAG, "onProviderDisabled: " + provider);
}

@Override
public void onProviderEnabled(String provider) {
Log.e(TAG, "onProviderEnabled: " + provider);
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.e(TAG, "onStatusChanged: " + provider);
}
}

LocationListener[] mLocationListeners = new LocationListener[]{
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};

@Override
public IBinder onBind(Intent arg0) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
LocationInitialize();
return START_STICKY;
}

@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startMyOwnForeground();
} else {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "1");
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("My service.")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(1, notification);
}
}

@RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground() {
String channelName = "My service";
NotificationChannel chan = new NotificationChannel("2", channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "2");
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("My service")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2, notification);
}

public void LocationInitialize(){
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[1]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "network provider does not exist, " + ex.getMessage());
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[0]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "gps provider does not exist " + ex.getMessage());
}
}

@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
// no need to do anything here
//Intent broadcastIntent = new Intent();
//broadcastIntent.setAction("restartservice");
//broadcastIntent.setClass(this, RestartService.class);
//this.sendBroadcast(broadcastIntent);
}

private void initializeLocationManager() {
Log.e(TAG, "initializeLocationManager");
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}

@Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());

PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);

super.onTaskRemoved(rootIntent);
}
}

Android back ground service with location listener

greeble31 Answer: Your app and its service are most likely being destroyed in order to free up resources. See here. You may want to go with a foreground service instead.



Related Topics



Leave a reply



Submit