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