Home > Software engineering >  How to list API call results in Jetpack Compose
How to list API call results in Jetpack Compose

Time:01-20

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.

  • Related