Pablo
04/11/2025, 5:01 PMprivate fun updateUiState() {
viewModelScope.launch {
sensorsDataUseCase.invoke().collect { sensorsData ->
_uiState.update { currentState -> currentState.copy(sensorsData = sensorsData) }
}
}
}
The problem here is that when the screen goes background, the flow is still emitting data. How can I stop collecting the data when the viewmodel screen is in foreground? I have a uistate onScreen: Boolean
variable which is se to true on screen onResume and to false on screen onPause, so it seems to be a perfect fit for this case. But I don't know how to use it to stop collecting the data, or how to cancel it by a cleaner wayPablo
04/11/2025, 5:20 PMprivate var sensorsDataJob: Job? = null
variable in the viewmodel which stores the corutine job that launches the flow recollection, and I cancel it when onResume gets notified to the viewmodel, it seems to work, but I'm not sure this is the correct way to do thingsPablo
04/11/2025, 5:21 PMLifecycleResumeEffect(Unit) {
vm.onResume()
onPauseOrDispose {
vm.onPause()
}
}
Stylianos Gakis
04/11/2025, 6:22 PMPablo
04/11/2025, 6:53 PMPablo
04/11/2025, 6:54 PMPablo
04/11/2025, 6:54 PMPablo
04/11/2025, 6:55 PMStylianos Gakis
04/11/2025, 7:12 PMPablo
04/11/2025, 9:13 PMPablo
04/11/2025, 9:13 PMPablo
04/11/2025, 9:13 PMStylianos Gakis
04/11/2025, 9:17 PMPablo
04/11/2025, 9:18 PMPablo
04/11/2025, 9:19 PMPablo
04/11/2025, 9:22 PMPablo
04/11/2025, 9:22 PMPablo
04/11/2025, 9:23 PMPablo
04/11/2025, 9:23 PMPablo
04/11/2025, 9:23 PMPablo
04/11/2025, 9:23 PMPablo
04/11/2025, 9:24 PMStylianos Gakis
04/11/2025, 10:43 PMPablo
04/17/2025, 1:57 PMprivate fun updateUiState() {
viewModelScope.launch {
// on start, update everything
_uiState.update { currentState ->
currentState.copy(
summaryPageContent = specificationsUseCase.getSummaryInfo(),
systemPageContent = specificationsUseCase.getSystemInfo(),
loading = false
)
}
// observe changes in current page of uistate pager state, to enable or disable sensor data
// collection if the current page is sensor page
launch {
snapshotFlow { _uiState.value.pagerState.currentPage }
.distinctUntilChanged()
.collect { currentPage ->
if (Page.entries[currentPage] == Page.SENSORS) {
startSensorsDataCollection()
} else {
stopSensorsDataCollection()
}
}
}
// later, after each 500 ms, conditional update
while (isActive && _uiState.value.onScreen) {
delay(500)
_uiState.update { currentState ->
val currentPage = Page.entries[currentState.pagerState.currentPage]
currentState.copy(
summaryPageContent = if (shouldUpdatePage(currentPage, Page.SUMMARY)) specificationsUseCase.getSummaryInfo() else currentState.summaryPageContent,
systemPageContent = if (shouldUpdatePage(currentPage, Page.SYSTEM)) specificationsUseCase.getSystemInfo() else currentState.systemPageContent,currentState.sensorsPageContent,
loading = false
)
}
}
}
}
Pablo
04/17/2025, 1:57 PMPablo
04/17/2025, 2:01 PMfun onResume() {
_uiState.update { currentState -> currentState.copy(onScreen = true) }
updateUiState()
}
fun onPause() {
_uiState.update { currentState -> currentState.copy(onScreen = false) }
stopSensorsDataCollection()
}
private fun stopSensorsDataCollection() {
sensorsDataJob?.cancel()
sensorsDataJob = null
}
Pablo
04/17/2025, 2:02 PMLifecycleResumeEffect(Unit) {
vm.onResume()
onPauseOrDispose {
vm.onPause()
}
}
Pablo
04/17/2025, 2:02 PMPablo
04/17/2025, 2:03 PMPablo
04/17/2025, 2:04 PMprivate fun startSensorsDataCollection() {
if (sensorsDataJob?.isActive == true) return
sensorsDataJob = viewModelScope.launch {
sensorsDataUseCase.invoke().collect { sensorsData ->
_uiState.update { currentState ->
currentState.copy(sensorsData = sensorsData.toList())
}
}
}
}
Pablo
04/17/2025, 2:05 PM// job used for store sensors data flow corutine and being able to cancel recollection when screen in background
private var sensorsDataJob: Job? = null
Pablo
04/17/2025, 2:05 PMPablo
04/17/2025, 6:10 PMPablo
04/22/2025, 10:41 AMprivate val _uiState = MutableStateFlow(SpecificationsScreenUiState(loading = true))
val uiState: StateFlow<SpecificationsScreenUiState> = _uiState
// Job for periodic UI updates
private var periodicUpdateJob: Job? = null
// Job for sensor data collection
private var sensorsDataJob: Job? = null
init {
// Observe changes in the pager state to manage sensor data collection
viewModelScope.launch {
snapshotFlow { _uiState.value.pagerState.currentPage }
.distinctUntilChanged()
.collect { currentPage ->
if (Page.entries[currentPage] == Page.SENSORS) {
startSensorsDataCollection()
} else {
stopSensorsDataCollection()
}
}
}
// Automatically start or stop periodic updates based on active uiState subscribers.
viewModelScope.launch {
_uiState.subscriptionCount.collect { count ->
if (count > 0) {
startPeriodicUpdateJob()
// Explicitly check if current page is sensors and restart sensor collection
if (Page.entries[_uiState.value.pagerState.currentPage] == Page.SENSORS) {
startSensorsDataCollection()
}
} else {
stopPeriodicUpdateJob()
stopSensorsDataCollection() // Stop sensor collection when not visible
}
}
}
}
private fun startSensorsDataCollection() {
if (sensorsDataJob?.isActive == true) return
sensorsDataJob = viewModelScope.launch {
sensorsDataUseCase.invoke().collect { sensorsData ->
_uiState.update { currentState ->
currentState.copy(sensorsData = sensorsData.toList())
}
}
}
}
private fun stopSensorsDataCollection() {
sensorsDataJob?.cancel()
sensorsDataJob = null
}
// This job performs a full update initially and then periodic updates every 500 ms.
private fun startPeriodicUpdateJob() {
if (periodicUpdateJob?.isActive == true) return
periodicUpdateJob = viewModelScope.launch {
// Perform an initial complete update.
updateAllPages()
// Then, periodically update only the visible pages.
while (isActive) {
delay(500)
updateOnlyVisiblePages()
}
}
}
private fun stopPeriodicUpdateJob() {
periodicUpdateJob?.cancel()
periodicUpdateJob = null
}