简体   繁体   中英

how to call LazyRow after API response Jetpack Compose

Im learning Jetpack Compose and Kotlin, what I need to do is populate a lazyrow with some info from an api, but it seems that Im doing something wrong, since the interface is created and a white screen is shown, in the log I can see that API is called and the response is the object I needed, but the lazyrow never gets recomposed again so the white screen stays like that.

This is my code

       @Composable
    fun ParentHomeComposable(
        parentSkills: List<ParentHomeResponseModel>,
    ){
        LazyRow{
            items(
                items = parentSkills,
                key = { parentSkills ->
                    parentSkills.studentId
                }
            ) { parentSkills ->
                ParentItemComposable(
                    ParentItem = parentSkills,
                )
            }
        }
    }
    
    @Composable
    fun ParentItemComposable(
        ParentItem: ParentHomeResponseModel,
    ) {
        BoxWithConstraints() {
            Box() {
                Column{
                    Box()
                    {
                        Text(
                            text = ParentItem.username,
                            color = DARK_GRAY,
                            fontWeight = FontWeight.Bold,
                            overflow = TextOverflow.Ellipsis,
                            maxLines = 2,
                            style = MaterialTheme.typography.h4,
                            textAlign = TextAlign.Center,
                        )
                    }
                }
            }
        }
    }


this is my viewmodel

    @HiltViewModel
    class ParentHomeViewModel @Inject
    constructor(
        private val getParentHomeUseCase: GetParentHomeUseCase,
    ) : ViewModel() {
        
        private val _uiState = MutableStateFlow(ParentHomeUiState())
        val uiState: StateFlow<ParentHomeUiState> = _uiState.asStateFlow()
    
        init {
            onGetParentHome()
        }
        
        private fun onGetParentHome() {
            viewModelScope.launch {
                _uiState.update { it.copy(isLoading = true) }
                val parentHomeResponse = getParentHomeUseCase.getParentHome()
                val parentHomeModel = parentHomeResponse.successOr(listOf())
                _uiState.update { parentHomeUiState ->
                    parentHomeUiState.copy(
                        parentHome = parentHomeModel,
                        isLoading = false
                    )
                }
            }
        }
    }

my parenthomeUiState

    data class ParentHomeUiState(
        val parentHome: List<ParentHomeResponseModel> = listOf(),
        val isLoading: Boolean = false,
        val isDone: Boolean = false
        )


this is the log response

{
    "avatar": "TACO",
    "username": "fdsfss",
    "hodStreak": [false, false, false, false, false],
    "hodPoints": 0,
    "hodRanking": 0,
    "hodTopicsViewed": 15,
    "studentId": "630d786c25430056356c632c",
    "weekProgress": 25,
    "generalProgress": 50,
},
{
    "avatar": "MICHAELL",
    "username": "sffgsf",
    "hodStreak": [false, false, false, false, false],
    "hodPoints": 0,
    "hodRanking": 0,
    "hodTopicsViewed": 15,
    "studentId": "630d901a25430056356c6460",
    "weekProgress": 25,
    "generalProgress": 50,
},

my response model
@Parcelize
data class ParentHomeResponseModel(
    val avatar: String = "",
    val username: String = "",
    val hodStreak: List<Boolean>,
    val hodPoints: Int = 0,
    val hodRanking: Int = 0,
    val hodTopicsViewed: Int = 0,
    val studentId: String = "",
    val weekProgress: Int = 0,
    val generalProgress: Int = 0,
    val exploredTopics:List<ExploredTopics>  ,
): Parcelable{}

any ideas? I thought this was really easy but its not working for me

I will guess a little based on information on your code

ParentHomeComposable(...)

takes a list of type List<ParentHomeResponseModel>

The problem is that this composable is rendered at first time you compose it (let's say on activity / navigation / fragment start, or when your open this composable with setContent) and without any state that the composable needs to know about it will never change, it will be rendered once.

Now I'm assuming that your are listening to the data inside your activity/fragment like this

viewModel.uiState.collect  { yourData ->
   ParentHomeComposable(yourData.parentHome)
}

but instead you should be doing

  @Composable
    fun ParentHomeComposable(
        parentSkills: List<ParentHomeResponseModel>,
    ){
        val uiState = viewModel.uiState.observeAsState()
        LazyRow{
            items(
                items = uiState.parentHome,
                key = { parentSkills ->
                    parentSkills.studentId
                }
            ) { parentSkills ->
                ParentItemComposable(
                    ParentItem = parentSkills,
                )
            }
        }
    }

This code will provide a state to the LazyRow .

So, when the viewmodel provides a new uiState , it will be collected inside the composable and recompose based on the new data.

For more information take a look here

https://developer.android.com/jetpack/compose/architecture

You will get a richer information here

https://developer.android.com/jetpack/compose/lifecycle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM