1

I cannot seem to create an infinite loop that runs periodically for a background service and is reliable.

The app uses a Service to post a GPS location every 5 seconds using a FusedLocationClient LocationCallback.

The functions loop as expected when running on the main thread, however the functions stop looping shortly after starting a different app. This is the case for a new thread, as well as a background service, and even a new thread created by a background service, it consistently stops looping shortly after starting a different app. Shortly thereafter onDestroy() is called.

The only way I have been able to successfully continue looping a function in a Service while the user is in a different app is by having a while(true) loop. However, when I implement this method, I never get a call back from the FusedLocationClient. I cannot figure out why or how to get around this problem.

I have already reviewed the Android Guides and API documentation for Background processing, Background Service, Handler, Looper, Thread.

As well as the StackExchange questions:how to run infinite loop in background thread and restart it, How to run an infinite loop in Android without freezing the UI.

My question is how do I maintain a continuous loop in a background service that does not interfere with the UI AND does not interfere with the FusedLocationCallback

Below is a snippet of my code. And yes, I declared everything correctly in the manifest.

class MyService: Service(){

private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
private lateinit var looper: Looper
private lateinit var context: Context
data class postGPS(...)

val runnable: Runnable = object : Runnable {
    override fun run() {
        getLocation()
    }
}

override fun onStartCommand(...): Int {
    context = this
    val thread = BackgroundThread()
    thread.start()
    return START_STICKY
}

inner class BackgroundThread: Thread(){
override fun run() {
    Looper.prepare()
    looper = Looper.myLooper()!!
    handler = Handler(looper)
    getLocation()
    Looper.loop()
    }
}
@SuppressLint("MissingPermission")
fun getLocation()
{
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
    locationRequest = LocationRequest()
    locationRequest.interval = 1000
    locationRequest.fastestInterval = 1000
    locationRequest.smallestDisplacement = 10f
    locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
            locationResult ?: return
            if (locationResult.locations.isNotEmpty()) {
                PostGPS(postGPS(locationResult.lastLocation)
            }
        }
    }
    fusedLocationClient.requestLocationUpdates(
        locationRequest,
        locationCallback,
        looper
    )
}

    private fun PostGPS(gps: postGPS){
    val queue = Volley.newRequestQueue(context)
    val url = "https://www.URL.com/api"
    val stringReq: StringRequest =
        object : StringRequest(
            Method.POST, url,
            Response.Listener { response ->
                Toast.makeText(context, response, Toast.LENGTH_SHORT).show()
                handler.postDelayed(runnable,5000) //Loop for posting GPS location
            },
            Response.ErrorListener { error ->
                Toast.makeText(context, error.message.toString(),Toast.LENGTH_SHORT).show()
            }
        ) {

            override fun getBody(): ByteArray {
                return gps.toByteArray(Charset.defaultCharset())
            }
        }
    queue.add(stringReq)
}
override fun onBind(intent: Intent): IBinder? {
    return null
}

override fun onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
}
}
  • 1
    Background services are only allowed to run for so long (a few minutes) after their app is no longer foreground. A ForegroundService can run indefinitely, but may also be killed under various circumstances. Also, these days Android allows the user to only allow location gathering while the app is in the foreground. Constantly running background tasks sending location to a webservice is something Google actively does not want for privacy and batter reasons, and if you are doing it they want it to be very visible and controllable by users. – Gabe Sechan Dec 08 '21 at 17:51
  • "The app uses a Service to post a GPS location every 5 seconds" -- from a battery usage standpoint, this is truly awful. You are going to have a lot of difficulty implementing this, as both Google and device manufacturers are going to try to protect users from apps that do this sort of thing (see Doze mode, app standby, and https://dontkillmyapp.com/). – CommonsWare Dec 08 '21 at 17:59
  • Thank you @Gabe Sechan, I did a lot more research into foreground services(which I had tried using before with no luck), turns out there is an additional tag needed in the manifest for the service to access locations. Thank you for your comment! – Eli Sternbach Dec 09 '21 at 13:30

0 Answers0