Android ViewModel: check network connectivity state
As you know ViewModel
should not use Context
. Yes, there is AndroidViewModel
but if you want to keep ViewModel
as flat as possible (or if you use Koin as me) — welcome under the hood.
The problem
We need to observe connectivity changes and propagate them to ViewModel. Inside ViewModel there are several use cases when we need to check connectivity state:
- Before performing a network request.
- Cancel Retrofit calls on connectivity brake.
Solution
All you need is ConnectionLiveData!
class ConnectionLiveData(private val context: Context) : LiveData<Boolean>() {
private val networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
postValue(context.isConnected)
}
}
override fun onActive() {
super.onActive()
context.registerReceiver(
networkReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
}
override fun onInactive() {
super.onInactive()
try {
context.unregisterReceiver(networkReceiver)
} catch (e: Exception) {
}
}
}val Context.isConnected: Boolean
get() = (getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager)?.activeNetworkInfo?.isConnected == true
In your BaseActivity
add:
protected lateinit var connectionLiveData: ConnectionLiveData
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
connectionLiveData = ConnectionLiveData(this)
}
In child’s onCreate
:
connectionLiveData.observe(this) {
viewModel.isNetworkAvailable.value = it
}
viewModel.isNetworkAvailable.value = isConnected
Instant value initialization is needed because it takes some time until broadcast receiver will be registered and connectionLiveData
emits its first value.
How to use it:
fun runAsyncWithRetry(callback: suspend () -> Unit) {
if (isNetworkAvailable.value == true) {
_state.value = UiState.IN_PROGRESS
job = viewModelScope.launch {
callback.invoke()
_state.value = UiState.LOADED
}
} else {
_error.value = UiError.Resource(R.string.error_network)
_state.value = UiState.SHOW_RETRY
}
}
Conclusion
That’s all! Thanks for your attention.
Also you may consider reading my another publication about how to properly handle network issues and cancel Retrofit operations using Kotlin Coroutines.