Android ViewModel: check network connectivity state

Alex Zaitsev
2 min readJan 23, 2020

--

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:

  1. Before performing a network request.
  2. 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.

--

--

Alex Zaitsev

Migrating to https://alexzaitsev.substack.com, follow me there! #android #mobile #kmp #kmm #kotlin #multiplatform #flutter #crossplatform