I am trying to build a simple listing app and to fetch data from url I use retrofit2. And then, I store in MutableLiveData<Resource> object. How can I list retrofit2 results in LazyColumn?
My composable:
@ExperimentalAnimationApi
@Composable
fun CarsScreen(
viewModel: CarListViewModel = hiltViewModel()
){
viewModel.getCarsFromAPI()
val carsLiveData = viewModel.carsLiveData.observeAsState()
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
){
GreetingSection()
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
itemsIndexed( ){
//TODO
}
}
}
Viewmodel:
@HiltViewModel
class CarListViewModel @Inject constructor(
private val carRepository: CarRepository
): ViewModel() {
val carsLiveData:MutableLiveData<Resource<CarsResponse>> = MutableLiveData()
fun getCarsFromAPI() = viewModelScope.launch {
carsLiveData.postValue(Resource.Loading())
val response = carRepository.getCarsFromAPI()
carsLiveData.postValue(handleCarResponse(response))
}
private fun handleCarResponse(response: Response<CarsResponse>) : Resource<CarsResponse> {
if(response.isSuccessful){
response.body()?.let{resultResponse ->
return Resource.Success(resultResponse)
}
}
return Resource.Error(response.message())
}
}
CodePudding user response:
observeAsState
doesn't return a LiveData
; it returns the data contained within the LiveData
that you're observing.
Whenever that LiveData
's value changes, recomposition is triggered, and you'll get a new value.
Change the name of property carsLiveData
to just cars
. You can use that directly as the items in your LazyColumn
.
One other note - you're calling viewModel.getCarsFromAPI()
inside the CarsScreen
composable every time it's recomposed. You probably don't want to do that.
If you only want to get the list once, you could use a LaunchedEffect
inside CarsScreen
, something like:
// Copyright 2023 Google LLC.
// SPDX-License-Identifier: Apache-2.0
@Composable
fun CarsScreen(...) {
LaunchedEffect(Unit) {
viewModel.getCarsFromAPI()
}
...
}
If you want to update that list, pass some state into LaunchedEffect
instead of Unit - whenever that state changes, the LaunchedEffect
will be canceled (if currently running) and restarted.