0

i have a issue with a lazy column and a database. When i load my activity with a lazy column, the database is call to get list of tournaments. But the list is not display in the lazy column. The list is display the moment after i click to change of page/activity although it makes sense.

DAO:

@Dao
interface TournamentDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insert(tournament: TournamentEntity)

    @Update
    suspend fun update(tournament: TournamentEntity)

    @Delete
    suspend fun delete(tournament: TournamentEntity)

    @Query("SELECT * from tournaments WHERE id = :id")
    fun getItem(id: Int): Flow<TournamentEntity>

    @Query("SELECT * from tournaments ORDER BY id ASC")
    fun getAllItems(): Flow<List<TournamentEntity>>

}

REPOSITORY:

class OfflineTournamentRepository(private val tournamentDao: TournamentDao):TournamentRepository {
    override fun getAllStream(): Flow<List<TournamentEntity>> = tournamentDao.getAllItems()

    override fun getStream(id: Int): Flow<TournamentEntity?> = tournamentDao.getItem(id)

    override suspend fun insert(tournament: TournamentEntity) = tournamentDao.insert(tournament)

    override suspend fun delete(tournament: TournamentEntity) = tournamentDao.delete(tournament)

    override suspend fun update(tournament: TournamentEntity) = tournamentDao.update(tournament)
}

VIEW MODEL:

class TournamentListViewModel(private val tournamentRepository: TournamentRepository):ViewModel() {
    private val _uiState = MutableStateFlow(TournamentListState())
    var uiState: StateFlow<TournamentListState> = _uiState.asStateFlow()
        private set

    fun updateUiState(tournaments: List<Tournament>) {
        _uiState.value.tournaments=tournaments
    }

    private suspend fun getAll(){
        _uiState.value.tournaments=tournamentRepository.getAllStream().first().map { it.toModel() }
    }

    init{
        viewModelScope.launch {
            getAll()
        }

    }

}

STATE:

class TournamentListState(
    var tournaments: List<Tournament> = listOf(),
) {
}

LAZY COLUMN OF ACTIVITY:

LazyColumn(
            modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight(0.91f)
                .padding(0.dp, 10.dp, 0.dp, 0.dp),
            verticalArrangement = Arrangement.spacedBy(10.dp)
        ) {
            items(tournamentListViewModel.uiState.value.tournaments){ tournament: Tournament ->
                TournamentItemCard(
                    tournament = tournament,
                    modifier = Modifier
                        .fillParentMaxWidth()
                        .fillParentMaxHeight(0.1f)
                )
            }
        }

Please what i have to change for the list display when data arrives?

5
  • How about observing your state in Compose side like val uiState = tournamentListViewModel.uiState.collectAsState() and then passing tournament list in your LazyColumn's item like items(uiState.tournaments)? Commented Nov 15, 2023 at 6:02
  • Unfortunately it doesn't change the result. Commented Nov 15, 2023 at 19:37
  • along with the previous comment's change, please also change the code inside the method of getAll() in your viewModel like this: _uiState.value = _uiState.value.copy(tournaments = tournamentRepository.getAllStream().first().map { it.toModel() } and also change your TournamentListState into data class Commented Nov 16, 2023 at 3:02
  • Thank you, that works. Please, according to you, what is the reason? Commented Nov 16, 2023 at 17:16
  • I have added the reason in answer with some changes in your code. Commented Nov 17, 2023 at 6:48

1 Answer 1

0

I think the reason might be you are not observing state. Which in turn doesn't know the inner property (tournaments) changes of your uiState variable. Compose needs state to recompose. So, as it doesn't know your state change and it wasn't recomposing to show the data. When the state changes (e.g. after click) the it recomposes with the already loaded data thus showing the list. The resolution is that, you observe your state change in your compose side and update the state in your StateHolder (ViewModel in your case) whenever you get new data.
The below way will show your list in UI whenever it's available in ViewModel side with some minor optimization.
Change your TournamentListViewModel to:

class TournamentListViewModel(private val tournamentRepository: TournamentRepository):ViewModel() {
    private val _uiState = MutableStateFlow(TournamentListState())
    val uiState: StateFlow<TournamentListState> = _uiState.asStateFlow() // <- Changed to val as it doesn't need to be Mutable and being accessed outside StateHolder

    fun updateUiState(tournaments: List<Tournament>) {
        _uiState.value.tournaments = tournaments
    }

    private suspend fun getAll() {
        _uiState.value = _uiState.value.copy(tournaments = tournamentRepository.getAllStream().first().map { it.toModel() } // <- Changed to updating state with new value instead of inner property so that your UI is notified of data changes
    }

    init {
        viewModelScope.launch {
            getAll()
        }
    }
}

Changing your TournamentListState class into data class. Also add state observing property in your UI side (LazyColumn's place in your case) like below.

val uiState = tournamentListViewModel.uiState.collectAsState()
LazyColumn(
    modifier = Modifier
        .fillMaxWidth()
        .fillMaxHeight(0.91f)
        .padding(0.dp, 10.dp, 0.dp, 0.dp),
    verticalArrangement = Arrangement.spacedBy(10.dp)
) {
    items(uiState.value.tournaments){ tournament: Tournament ->
        TournamentItemCard(
            tournament = tournament,
            modifier = Modifier
                .fillParentMaxWidth()
                .fillParentMaxHeight(0.1f)
        )
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.