3

I'm fairly new to Jetpack Compose. Currently, I have a ViewModel making 1 network call.

class PlatformViewModel @Inject constructor(
  private val getProductListUseCase: GetListUseCase
) : ViewModel() 

I had 3 states.

sealed class PlatformState {
  object Loading : PlatformState()
  data class Success(val listOfProducts: List<Product>) : PlatformState()
  object Error : PlatformState()
}

In the UI, it Was easy to handle observing 1 live data.

val state = viewModel.platformState.observeAsState(PlatformState.Loading)

when (state) {
  is PlatformState.Success -> SuccessView(listOfProducts = state.listOfProducts)
  is PlatformState.Loading -> LoadingView()
  is PlatformState.Error -> ErrorView()
}

now, I need to add 1 more network call in viewModel for the same screen

class PlatformViewModel @Inject constructor(
  private val getProductListUseCase: GetListUseCase,
  private val getHeaderUseCase: GetHeaderUseCase,
) : ViewModel() 

-Should I add 3 more states and 1 more live data to observe for the UI, what is the best way to handle this?

Note: both network calls are unrelated but their result populates the same composable.

fun bodyContent(listOfProducts:List<Products>,headerDetails:HeaderDetails){
LazyColumn{
    item{ HeaderDetails(details=headerDetails)}
    items(listOfProducts.size){
        ProductItem()
}
theukvisitor
  • 131
  • 1

1 Answers1

0

Since the composable function, bodyContent requires both parameters listOfProducts:List<Products>, headerDetails:HeaderDetails.

I would create a data class that holds those values and that class should be sent to the composable function.

data class BodyContentUIData(listOfProducts:List<Products>, headerDetails:HeaderDetails)

The composable should be

fun BodyContent(bodyContentUIData: BodyContentUIData) {
    LazyColumn {
        item { HeaderDetails(details = bodyContentUIData.headerDetails) }
        items(bodyContentUIData.listOfProducts.size) {
            ProductItem()
        }
    }
}

//BTW, composable functions should start with a capital case.

At the view model, You should have a function called getBodyContentData that first calls getHeaderUseCase and if it's a success then call getProductListUseCase after the success you'll be having the listOfProducts and the headerDetails now you create the data class and send it to the composable function.

The view model could look like this:

class PlatformViewModel @Inject constructor(
    private val getProductListUseCase: GetListUseCase,
    private val getHeaderUseCase: GetHeaderUseCase,
) : ViewModel() {
    fun getBodyContentData() {
        getHeaderUseCase().onSuccess { headerDetails ->
            getProductListUseCase().onSuccess { listOfProducts ->
                _bodyContentLiveData.value = SuccessView(BodyContent(headerDetails, listOfProducts))
            }
        }
    }
}

This way you have just 1 live data and 3 states for the composable.

  • 1
    Yes but, these network calls are unrelated and in my opinion, the List network call shouldn't be waiting for the header network call to finish and the same in UI both header and List shouldn't depend on each other. Also according to your code if the header network call fails then it won't call list API. I don't think this is the best practice. – theukvisitor Nov 10 '22 at 14:18
  • Even though they're not related to each other, both of them are useless without the other because of how you use them at the compostable, I'd header API failed, then it doesn't make sense to get the details, How are you going to use the details without the header? Unless you change the way you're displaying them to the UI. – Mohamed Habib Nov 13 '22 at 03:34
  • details and header are unrelated information, the header consists of the hero image of the screen and certain information about the app, while details are the list of products. they are on the same screen but in different sections, totally unrelated to each other. – theukvisitor Nov 17 '22 at 10:46