androidandroid-roomandroid-room-relation

Retrieve data from room in android


I am pulling data from the room database, function returns data that I need, it gets displayed in the lazy column for seconds and then goes blank.

class TrainViewModel(private val cRepository: CRepository) : ViewModel() {
private val _trainList = MutableStateFlow<List<TrnTable>>(emptyList())
val trainList: StateFlow<List<TrnTable>> get() = _trainList

fun loadTrains() {
    viewModelScope.launch {
        cRepository.getAllTrains().collect { trains ->
            _trainList.value = trains
        }
    }
}

}

Displaying it in LazyColumn

    @Composable
fun TrainListScreen(viewModel: TrainViewModel) {
    val trainList by viewModel.trainList.collectAsState()

    Column {
        Button(onClick = { viewModel.loadTrains() }) {
            Text("Load Trains")
        }

        LazyColumn {
            items(trainList) { train ->
                Text(text = train.name)
            }
        }
    }
}

but when I use this approach, data is retrieved properly.

val allTrains: Flow<List<TrnTable>> = cRepository.getAllTrains()

But I have around 12k trains, which approach would be more efficient?

Repository-

 fun getAllTrains(): Flow<List<TrnTable>> {
    return trainDao.getTrains()
}

DAO-

@Query("SELECT * FROM Trn")
abstract  fun getTrains(): Flow<List<TrnTable>>

Entity-

 @Entity("Trn")
data class TrnTable(
    @PrimaryKey
    val number:String="",
    val name:String="",
    val fromStnCode:String="",
    val fromStnName:String="",
    val toStnCode:String="",
    val toStnName:String="",)

Solution

  • You seem to have already figured out the solution for yourself. To make it more explicit: Do not collect flows in the view model. Use this instead:

    val trainList: StateFlow<List<TrnTable>> = cRepository.getAllTrains()
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5_000),
            initialValue = emptyList(),
        )
    

    This has nothing to with how many entries you have in the database. It does the same as your previous code, but in a proper way. Talking about proper: You should use collectAsStateWithLifecycle in your composables instead of collectAsState.

    The rest of your question seems to be concerned about the performance and/or memory footprint when all entries are loaded at once. 12k entries of type TrnTable doesn't seem too much to me, though. You can always page your data so you only ever select parts of the entries, but since this is more complex and produces an overhead I would do this only when you have strong indicators that this actually is a problem that needs to be addressed. Don't fall in the trap of Premature optimization.