Network state utils package is just a small package that offers some tools to make handling network states and events a breeze!
To install simply add the package to your dependencies add jitpack to root build gradle:
allprojects {
repositories {
// ...
maven { url 'https://jitpack.io' }
}
}
Then add the dependency to your module gradle.
dependencies {
implementation 'com.github.JimmyMcBride:NetworkStateUtilsLib:1.0.1'
}
NetworkState
is a sealed class to handle... you guessed it, our network state.
sealed class NetworkState<out T> {
object Idle : NetworkState<Nothing>()
object Loading : NetworkState<Nothing>()
data class Success<T>(val data: T) : NetworkState<T>()
data class Error(val message: String) : NetworkState<Nothing>()
}
duringState
is an extension function for NetworkState
that helps us handle what happens during
any given state the network request is in.
networkEvent.duringState(
success = { data -> onSuccess(data) },
error = { message -> onError(message) },
loading = { onLoading() },
idle = { onIdle() }
)
Very similar to duringState
but allows you to add composable functions inside each state block.
networkEvent.DuringComposableState(
success = { data ->
Text(data.name)
},
error = { message ->
Text("N/A")
showSnackbar(message)
},
loading = { CircularProgressIndicator() },
idle = {}
)
Sometimes you'll want to reset the NetworkState
back to Idle after a specific even has occurred. Be
sure to include a clean up function resetting NetworkState
back to idle in the view model for
ConsumeNetworkEvent
to use.
@HiltViewModel
class CitiesViewModel @Inject constructor(
private val cityUseCases: CityUseCases
) : ViewModel() {
private var _cities = cityUseCases.getCitiesUseCase(viewModelScope)
val cities: State<NetworkState<List<City>>> = _cities
private val _addCityEvent = mutableStateOf<NetworkState<Int>>(NetworkState.Idle)
val addCityEvent: State<NetworkState<Int>> = _addCityEvent
fun addCity(city: CityBody) {
_addCityEvent.value = NetworkState.Loading
viewModelScope.launch {
delay(2000L)
_addCityEvent.value = cityUseCases.addCityUseCase(city).duringState(
success = {
fetchCities()
}
)
}
}
fun consumeAddCityEvent(triggeredBlock: () -> Unit) {
triggeredBlock()
_addCityEvent.value = NetworkState.Idle
}
}
ConsumeNetworkEvent(
networkEvent = addCityEvent,
consumeEvent = citiesViewModel::consumeAddCityEvent,
onSuccess = {
isLoading = false
navController.popBackStack()
},
onError = {
isLoading = false
},
onLoading = { isLoading = true }
)
handleNetworkException
and handleResponse
are just some small utils to help up clean up our
repository.
fun <T> Response<T>.handleResponse(errorMessage: String = "Something went wrong.") =
if (this.isSuccessful && this.body() != null)
NetworkState.Success(data = this.body()!!)
else
NetworkState.Error(message = errorMessage)
suspend fun <T> handleNetworkException(apiCall: suspend () -> NetworkState<T>) = try {
apiCall()
} catch (e: Exception) {
NetworkState.Error(message = e.message.toString())
}
class RepositoryImpl(
private val citiesApi: CitiesApi,
) : Repository {
override suspend fun getCities(): NetworkState<List<City>> =
handleNetworkException { citiesApi.getCites().handleResponse() }
}
If you have any questions feel free to email me @ hello@jimmymcbride.dev or leave an issue on this repository if you notice and bugs or have any requests.