I'm trying to figure out how to send offline data to the server using a POST request when the device is connected to wifi or data.
How do I implement this process?
For that it will be necessary to monitor when the user will be connected. An easy way is using the ConnectivityManager
, but the minSdk
must be 24
or higher.
Note: I'm assuming you're using Kotlin
because you didn't specify the language but used the Compose
tag before post edit.
enum class ConnectivityStatus {
Available, Losing, Lost, Unavailable
}
class ConnectivityObserver(context: Context) {
private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
fun observe(): Flow<ConnectivityStatus> = callbackFlow {
val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
launch { send(ConnectivityStatus.Available) }
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
launch { send(ConnectivityStatus.Losing) }
}
override fun onLost(network: Network) {
super.onLost(network)
launch { send(ConnectivityStatus.Lost) }
}
override fun onUnavailable() {
super.onUnavailable()
launch { send(ConnectivityStatus.Unavailable) }
}
}
connectivityManager.registerDefaultNetworkCallback(networkCallback)
awaitClose {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}.distinctUntilChanged()
}
In this code example I was using an enum class
with some possible connection states and a class that returns a flow
with the respective states according to the user's connection through ConnectivityManager.NetworkCallback
.
Now we can observe the states (preferably inside a ViewModel
) and trigger the appropriate actions.
// class to handle Retrofit methods
class MyRepository {
suspend fun doPost() {
// post something
}
}
// data class to hold states
data class MyState(
val isLoading: Boolean = false,
val hasPendingActions: Boolean = false,
val connectivityStatus: ConnectivityStatus = ConnectivityStatus.Unavailable,
// and so on...
)
class MyViewModel(
private val connectivityObserver: ConnectivityObserver,
private val myRepository: MyRepository
) : ViewModel() {
var state by mutableStateOf(MyState())
private set
init {
observeConnectivity()
}
// to call on screen
fun doThings() {
if (state.connectivityStatus == ConnectivityStatus.Available) {
state = state.copy(isLoading = true)
myRepository.doPost()
} else state = state.copy(hasPendingActions = true)
}
private fun observeConnectivity() = viewModelScope.launch {
connectivityObserver.observe().collect { status ->
when (status) {
ConnectivityStatus.Available -> {
state = state.copy(connectivityStatus = status)
if (state.hasPendingActions) {
state = state.copy(isLoading = true, hasPendingActions = false)
myRepository.doPost()
}
}
else -> {
state = state.copy(connectivityStatus = status)
}
}
}
}
}
Here is a YouTube video where I took the code example using the ConnectivityManager
with callbackFlow
.