I have a isLoading
state and I'm trying to show a CircularProgressIndicator
when the value is true
.
@Composable
fun ProductDetailScreen(
viewModel: ProductDetailViewModel = hiltViewModel()
) {
val productState = viewModel.productState.value
LazyColumn{
item {
if (productState.isLoading)
CircularProgressIndicator()
}
}
}
I'm using a Resource
class for my API call results and in the repository I use this class to wrap my request result.
The problem is, although I'm returning Resource.Loading
from the repository, the isLoading
state is not being updated from ViewModel
and the ProgressIndicator is not shown in my screen. What could be causing this behavior?
sealed class Resource<T>(
val data: T? = null,
val message: String? = null,
val errorType: ExceptionMapper.Type? = null
) {
class Success<T>(data: T?) : Resource<T>(data)
class Error<T>(message: String, errorType: ExceptionMapper.Type, data: T? = null) : Resource<T>(data, message, errorType)
class Loading<T>(isLoading: Boolean = true) : Resource<T>()
}
Repository:
override suspend fun getProductComments(productId: Int): Resource<List<Comment>> {
return try {
Resource.Loading<List<Comment>>()
delay(3000)
Resource.Success(apiService.getComments(productId))
} catch (t: Throwable) {
val mappedException = ExceptionMapper.map(t)
Resource.Error(message = t.message!!, errorType = mappedException.type)
}
}
ViewModel:
@HiltViewModel
class ProductDetailViewModel @Inject constructor(
state: SavedStateHandle,
private val productRepository: ProductRepository
) : ViewModel() {
private val passedProduct = state.get<Product>(EXTRA_KEY_DATA)
var productId = passedProduct?.id
var productState = mutableStateOf(ProductState())
private set
init {
getProductComments()
}
private fun getProductComments() {
viewModelScope.launch {
productId?.let { pId ->
when (val commentResult = productRepository.getProductComments(pId)) {
is Resource.Success -> {
commentResult.data?.let { comments ->
productState.value =
productState.value.copy(
comments = comments,
error = null,
isLoading = false
)
}
}
is Resource.Error -> {
productState.value = productState.value.copy(
isLoadFailed = true,
isLoading = false,
error = commentResult.message
)
}
is Resource.Loading -> {
productState.value = productState.value.copy(
isLoadFailed = false,
isLoading = true,
error = null
)
}
}
}
}
}
}
CodePudding user response:
Your'e only checking this
is Resource.Loading -> {
...
}
when the repository returns, at this point its useless because when the call to getProductComments
is done, it's already Resource.Success
.
return try {
Resource.Loading<List<Comment>>() // you'll never get this value
delay(3000)
Resource.Success(apiService.getComments(productId))
So I'd suggest to update the ProductState
before you call the repository
private fun getProductComments() {
productState.value = productState.value.copy(isLoading = true)
viewModelScope.launch {
...
...
or set isLoading
to true as its initial state.
data class ProductState(
...
...
val isLoading : Boolean = true
...
)