I have a service running to track user location at a specific time interval. I have used foreground service for Oreo & post-Oreo devices and service for pre-Oreo devices. The service runs well when the app is minimised but when I remove the app from the minimised app list the service gets killed too. I have tested this on a Xiaomi device with Android 9. How I can keep the service running when the user kills the app.
Manifest:
<service android:name=".service.LocationService" />
MainActivity:
@OnClick(R.id.btn_start_tracking)
public void onClickStart(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.startForegroundService (new Intent (this, LocationService.class));
} else {
this.startService (new Intent (this, LocationService.class));
}
}
Service class goes here
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
public static final String TAG = LocationService.class.getSimpleName();
private static final long LOCATION_REQUEST_INTERVAL = 3000;
private static final float LOCATION_REQUEST_DISPLACEMENT = 5.0f;
private GoogleApiClient mGoogleApiClient;
private FusedLocationProviderClient mFusedLocationProviderClient;
private LocationRequest mLocationRequest;
private LocationCallback mLocationCallback;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d ("On Create-------> ","Inside on create");
buildGoogleApiClient();
showNotificationAndStartForegroundService();
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(LocationService.this);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
List<Location> locationList = locationResult.getLocations ();
for (Location loc : locationList) {
if (loc.getLatitude () != 0 && loc.getLongitude () != 0) {
Log.d (TAG,"Location -------------->>>>" + loc.getLatitude ()+ " " + loc.getLongitude ());
saveUserLocation (loc.getLatitude (),loc.getLongitude (),10990816+1);
break;
}
}
}
};
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d ("On Start Command---> ","Inside on Start Command");
return START_STICKY;
}
private synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
private void createLocationRequest() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(LOCATION_REQUEST_INTERVAL);
/* mLocationRequest.setSmallestDisplacement(LOCATION_REQUEST_DISPLACEMENT);*/
mLocationRequest.setFastestInterval (LOCATION_REQUEST_INTERVAL/2);
requestLocationUpdate();
}
private void requestLocationUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
mFusedLocationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
}
private void removeLocationUpdate() {
mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback);
}
/**
* This Method shows notification for ForegroundService
* Start Foreground Service and Show Notification to user for android all version
*/
private void showNotificationAndStartForegroundService() {
final String CHANNEL_ID = BuildConfig.APPLICATION_ID.concat("_notification_id");
final String CHANNEL_NAME = BuildConfig.APPLICATION_ID.concat("_notification_name");
final int NOTIFICATION_ID = 100;
NotificationCompat.Builder builder;
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_NONE;
assert notificationManager != null;
NotificationChannel mChannel = notificationManager.getNotificationChannel(CHANNEL_ID);
if (mChannel == null) {
mChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);
notificationManager.createNotificationChannel(mChannel);
}
builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name));
startForeground(NOTIFICATION_ID, builder.build());
} else {
builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name));
startForeground(NOTIFICATION_ID, builder.build());
}
}
@Override
public void onConnected(@Nullable Bundle bundle) {
createLocationRequest();
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
public void onTaskRemoved(Intent rootIntent) {
Log.d ("On Task Removed------> ","inside on task removed");
super.onTaskRemoved (rootIntent);
}
@Override
public void onDestroy() {
Log.d ("On Destroy","On destroy called in location service");
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
super.onDestroy();
}
private void saveUserLocation(Double lat,Double lon,Integer time){
LocationSaveRequest locationSaveRequest = new LocationSaveRequest ();
final List<com.vivacom.pi_sales_tracking.retrofit.locationsave.model.Location> locationList = new ArrayList<> ();
com.vivacom.pi_sales_tracking.retrofit.locationsave.model.Location location = new com.vivacom.pi_sales_tracking.retrofit.locationsave.model.Location ();
location.setUserId ("100");
location.setLat (lat);
location.setLon (lon);
location.setClientTimestampUtc (System.currentTimeMillis()/1000);
locationList.add (location);
locationSaveRequest.setLocations (locationList);
CallLocationSave.save ("KAKBDURKBJSBSKHGYBKA==", locationSaveRequest, new CallLocationSave.LocationSaveCallBack () {
@Override
public void onSuccess() {
locationList.clear ();
}
@Override
public void onFailure(LocationHistoryResponse locationHistoryResponse) {
locationList.clear ();
}
});
}
}