Stop Duplicate code For Check Retrofit response
Mozhdeh Nouri Sarani
Android Developer : Kotlin | Mentor | Technical Knowledge Sharing | Team Player
The problem that I often encountered in many projects related to HTTP requests was the need to handle both the success response and the error associated with the request. It required checking for success or error directly in the repository class, passing it to the presentation layer, and then re-checking the response in that layer.
sealed class ResultWrapper<out T> {
data class Success<out T>(val data: T) :ResultWrapperr<T>()
data class Error(val errorMessage: String? = null) :
ResultWrapperper<Nothing>()
}
In Repository :
class ForecastWeatherRepositoryImpl @Inject constructor(
private val forecastRemoteDataSource: ForecastWeatherRemoteDataSource,
@ApplicationContext val context: Context
) : WeatherForecastRepository {
override suspend fun getWeatherForecast(
latitude: Double, longitude: Double
): ResultWrapper<HourlyResponse> {
if (!isInternetAvailable(context)) {
return ResultWrapper.Error(error = "No Internet connection")
}
val result = forecastRemoteDataSource.getWeatherForecast(
latitude = latitude, longitude
= longitude
)
return when (result) {
is ResultWrapper.Success -> {
ResultWrapper.Success(
result.data.hourly.toHourlyDomainResponse())
}
is ResultWrapper.Error -> {
ResultWrapper.Error(error = result.error)
}
}
}
}
And Viewmodel class:
@HiltViewModel
class WeatherForecastHourlyViewModel @Inject constructor(
private val repository: WeatherForecastRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(ForecastHourlyState())
val uiState = _uiState.asStateFlow()
fun getForecastHourly(
latitude: Double,
longitude: Double
) = viewModelScope.launch {
_uiState.update {
it.copy(
hourlyForecast = null, loading = true,
errorMessage = null
)
}
when (val result = getWeatherForecast.invoke(
latitude = latitude,
longitude = longitude
)) {
is ResultWrapper.Success -> {
_uiState.update {
it.copy(
hourlyForecast = result.data?.getDetailsByHour(),
loading = false,
errorMessage = null
)
}
}
is ResultWrapper.Error -> {
_uiState.update {
it.copy(
hourlyForecast = null, loading = false,
errorMessage = result.error
)
}
}
}
}
}
}
I just only implement one request and we can see a lots of code consider we have more than one request? Actually we can use flow (combine)
I have come up with another solution:
First : extension function on ResultWrapper:
fun <T> ResultWrapper<T>.extractAppResponse(): Pair<T?, String?> =
when (this) {
is ResultWrapper.Success -> Pair(data, null)
is ResultWrapper.Error -> Pair(null, error)
}
Second:
Use it in Viewmodel like this:
@HiltViewModel
class WeatherForecastHourlyViewModel @Inject constructor(
private val getWeatherForecast: GetWeatherForecast
) : ViewModel() {
private val _uiState = MutableStateFlow(ForecastHourlyState())
val uiState = _uiState.asStateFlow()
fun getForecastHourly(
latitude: Double,
longitude: Double
) = viewModelScope.launch {
_uiState.update {
it.copy(loading = true)
}
val result = getWeatherForecast(latitude,
longitude).extractAppResponse()
_uiState.update {
it.copy(loading = false,
hourlyForecast = result.first?.getDetailsByHour(),
errorMessage = result.second
)
}
}
}
You can impelemt this with multiple request and save value in state class.
Give me your feedback in comment
Experienced Android Developer
1 å¹´We can use the Result<T> class in Kotlin and there is no need to create a wrapper class. The Result<T> class has good methods to handle this issue.
Android Developer @ Omidpay
1 å¹´I see cleaner approch on that extension fun??