I need to access location in the background when my app is running.
I successfully received location updates when my main activity implemented android.location.LocationListener
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
val criteria = Criteria()
val provider = locationManager.getBestProvider(criteria, false)
val location = locationManager.getLastKnownLocation(provider)
locationManager.requestLocationUpdates(provider, 5000, 20f, this)
setLocation(location)
} else {
/* ... */
}
However I attempted to add this code to a new service class (implementing both android.app.Service
and android.location.LocationListener
), and the onLocationChanged
function is only firing when the app is in view.
I believe this problem could be one of the following:
I think I read somewhere that I have to manually create a new thread inside the service so that it does not run on the same thread as the main activity. This could be the issue, but I haven't a clue how to do this. I'm new to android development and Kotlin.
I think I read somewhere that the location permissions I currently request aren't enough when accessing location in the background, but can't find out what to change.
I saw a solution somewhere where they create a timer that runs every few seconds and manually requests the last location from the location manager. I haven't tested this, but if it does work it doesn't satisfy my needs. The
requestLocationUpdates
allows me to configure both a minimum time and minimum distance. Of course I could manually add in a distance check, but this could affect battery life and performance.
How do I fix this problem?
(I can probably change any Java code to Kotlin if anyone is not familiar with Kotlin)
Edit 1
My service is definitely running, as the location updates are received in the foreground
Here is the
onStartCommand
code for my service:
override fun onStartCommand(intent: Intent, flags: Int, startid: Int): Int {
/* request location updates as above */
return START_STICKY
}
- Here is how I start the service in my main activity:
val serviceIntent = Intent(applicationContext, OnTheFlyLandmarkService::class.java)
startService(serviceIntent)
Edit 2
I also read that I need to display a notification to let users know that my service is running in the background. I tried the following code but this did not help:
val notification = NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.messageicon) .setContentTitle("My app") .setContentText("Accessing location in background...") .setAutoCancel(true) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .build() with(NotificationManagerCompat.from(this)) { notify(id, notification) }
Edit 3
I tried what @Michael said: call startForeground
inside the service and pass in the notification. This did not work, and I didn't even see a notification.
override fun onStartCommand(intent: Intent, flags: Int, startid: Int): Int {
val notification = buildNotification("My app", "Accessing location in background...")
startForeground(NOTIFICATION_ID_SERVICE, notification)
/* request location updates */
return START_STICKY
}