I use BroadcastReceiver to receive system notifications. When receiving a notification, I need to send some data to the server.
It’s important for me that receiving broadcasts and sending data works when the application is in background (this is its main task).
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class Airplane : BroadcastReceiver() {
@SuppressLint("UnsafeProtectedBroadcastReceiver")
@OptIn(DelicateCoroutinesApi::class)
override fun onReceive(context: Context, intent: Intent) {
Log.d("BroadcastReceiver", "ACTION_AIRPLANE_MODE_CHANGED")
val isAirplaneModeEnabled = intent.getBooleanExtra("state", false)
if (!isAirplaneModeEnabled) {
goAsync(GlobalScope, Dispatchers.Default) {
httpRequest()
}
}
}
private fun BroadcastReceiver.goAsync(
coroutineScope: CoroutineScope,
dispatcher: CoroutineDispatcher,
block: suspend () -> Unit
) {
val pendingResult = goAsync()
coroutineScope.launch(dispatcher) {
block()
pendingResult.finish()
}
}
private suspend fun httpRequest() {
// The request will not be fulfilled because we will not be able to connect to the network in time when flight mode is turned off. But that doesn't change the problem.
val client = HttpClient(CIO) {
expectSuccess = true
install(HttpTimeout) {
requestTimeoutMillis = 3000
}
}
try {
val response: HttpResponse = client.post("https://webhook.site") {
setBody("hello")
}
Log.d("response", response.status.toString())
} catch (e: Exception) {
Log.d("PostRequest", e.toString())
}
client.close()
}
}
Here is a sample code that works, at first glance. But if I turn airplane mode on and off for a short period of time, my BroadcastReceiver stops working. This only happens when the application is NOT in the foreground.
All the work inside goAsync is done in 1-2 seconds. I don’t understand why the system is disabling my BroadcastReceiver
Based on https://developer.android.com/develop/background-work/background-tasks#event-driven, my approach seems correct, but I’m probably missing something