Solution 1 :
Try this
public class BackgroundLocationUpdateService extends Service {
/**
* Author:Hardik Talaviya
* Date: 2019.08.3 2:30 PM
* Describe:
*/
private static final String TAG = "BackgroundLocation";
private Context context;
private FusedLocationProviderClient client;
private LocationCallback locationCallback;
private boolean stopService = false;
private Handler handler;
private Runnable runnable;
private NotificationCompat.Builder builder = null;
private NotificationManager notificationManager;
@Override
public void onCreate() {
Log.e(TAG, "Background Service onCreate :: ");
super.onCreate();
context = this;
handler = new Handler();
runnable = new Runnable() {
@Override
public void run() {
try {
requestLocationUpdates();
} catch (Exception e) {
e.printStackTrace();
} finally {
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(2));
}
}
};
if (!stopService) {
handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(2));
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.e(TAG, "onTaskRemoved :: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand :: ");
StartForeground();
if (client != null) {
client.removeLocationUpdates(locationCallback);
Log.e(TAG, "Location Update Callback Removed");
}
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "BackgroundService onDestroy :: ");
stopService = true;
if (handler != null) {
handler.removeCallbacks(runnable);
}
if (client != null) {
client.removeLocationUpdates(locationCallback);
Log.e(TAG, "Location Update Callback Removed");
}
}
private void requestLocationUpdates() {
LocationRequest request = new LocationRequest();
request.setFastestInterval(100)
.setInterval(200)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
client = LocationServices.getFusedLocationProviderClient(this);
final int[] permission = {ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)};
if (permission[0] == PackageManager.PERMISSION_GRANTED) {
final Location[] location = {new Location(LocationManager.GPS_PROVIDER)};
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
location[0] = locationResult.getLastLocation();
if (location[0] != null) {
Log.d(TAG, "location update " + location[0]);
Log.d(TAG, "location Latitude " + location[0].getLatitude());
Log.d(TAG, "location Longitude " + location[0].getLongitude());
Log.d(TAG, "Speed :: " + location[0].getSpeed() * 3.6);
if (notificationManager != null && client != null && !stopService) {
builder.setContentText("Your current location is " + location[0].getLatitude() + "," + location[0].getLongitude());
notificationManager.notify(101, builder.build());
}
}
}
};
client.requestLocationUpdates(request, locationCallback, null);
}
}
/*-------- For notification ----------*/
private void StartForeground() {
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT);
String CHANNEL_ID = "channel_location";
String CHANNEL_NAME = "channel_location";
notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
notificationManager.createNotificationChannel(channel);
builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
builder.setColorized(false);
builder.setChannelId(CHANNEL_ID);
builder.setColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
builder.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE);
} else {
builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
}
builder.setOnlyAlertOnce(true);
builder.setContentTitle(context.getResources().getString(R.string.app_name));
builder.setContentText("Your current location is ");
Uri notificationSound = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION);
builder.setSound(notificationSound);
builder.setAutoCancel(true);
builder.setSmallIcon(R.mipmap.ic_notification_app_icon);
builder.setContentIntent(pendingIntent);
startForeground(101, builder.build());
}
}
I hope this can help you!
Problem :
I am trying to get the current location of the device in foreground service using the Fused Location Provider Client in Android O. But the service is killed right after location request is made. I am thinking the service is killed because the fused location provider client gets the location in another background thread and when looking at the perspective of the service, it’s task is done. The issue is after service is destroyed no location update is received. How can I keep the service alive until service is specifically stopped?
My Service Class :
private val TAG = LocationService::class.java.simpleName
companion object {
val STOP_ACTION = "STOP_ACTION"
}
private lateinit var mFusedLocationClient: FusedLocationProviderClient
private lateinit var mLocationCallback: LocationCallback
private lateinit var notificationManager: NotificationManager
private val notificationId = 1
private val UPDATE_INTERVAL_IN_MILLISECONDS = 5000L
private val FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500L
private val CHANNEL_ID = TAG
override fun onHandleIntent(intent: Intent?) {
Log.d(TAG, "onHandleIntent start")
if (intent?.action.equals(STOP_ACTION)) {
Log.d(TAG, "stop service")
stopForeground(true)
stopSelf()
} else {
Log.d(TAG, "start location update")
createNotificationChannel()
val notificationIntent = Intent(this, OnboardingActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
0, notificationIntent, 0
)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Tracking realtime location")
.setContentText("Tap to open the application")
.setSmallIcon(R.drawable.logo)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build()
startForeground(notificationId , notification)
startLocationUpdates()
}
}
override fun onCreate() {
super.onCreate()
notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
for (location in locationResult.locations) {
Log.d(TAG, "$location")
}
}
override fun onLocationAvailability(p0: LocationAvailability?) {
super.onLocationAvailability(p0)
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e(TAG, "onStartCommand")
super.onStartCommand(intent, flags, startId)
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
mFusedLocationClient.removeLocationUpdates(mLocationCallback)
Log.e(TAG, "location service destroyed")
}
private fun startLocationUpdates() {
val mLocationRequest = LocationRequest()
mLocationRequest.interval = UPDATE_INTERVAL_IN_MILLISECONDS
mLocationRequest.fastestInterval = FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
try {
mFusedLocationClient.requestLocationUpdates(
mLocationRequest,
mLocationCallback,
Looper.myLooper()
)
} catch (e: SecurityException) {
Log.e(TAG, "Lost location permission. Could not request updates. $e")
}
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val nChannel = notificationManager.getNotificationChannel(CHANNEL_ID)
if (nChannel == null) {
val serviceChannel = NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager.createNotificationChannel(serviceChannel)
}
}
}
}
Any help is highly appreciated.
Comments
Comment posted by Harith Sankalpa
Thanks for your reply, but unfortunately this did not work for me. Instead, I used the main looper for the fused location provider client and made the service sleep until it’s specifically killed.