VisionBoardNameViewModel
I'm experiencing an issue where a ProgressDialog that displays loading information is persistently shown due to frequent recomposition of our Composable UI. This behavior is likely caused by how I manage and update data in our ViewModel and UseCase layers.
How can I solve this? Here is my code.
@HiltViewModel
class VisionBoardNameViewModel @Inject constructor(
val getLastBoardDataUseCase: GetLastBoardDataUseCase
) : ViewModel() {
private val _boardDataUiState = MutableStateFlow(BoardDataUiState())
val boardDataUiState: Flow<BoardDataUiState> = _boardDataUiState.asStateFlow()
fun getLastBoardData() = viewModelScope.launch {
getLastBoardDataUseCase().collectLatest { response ->
when (response) {
is Resource.Success -> {
_boardDataUiState.update { currentState ->
currentState.copy(boardData = response.data, isLoading = false)
}
}
is Resource.Failure -> {
_boardDataUiState.update { currentState ->
currentState.copy(error = response.message, isLoading = false)
}
}
is Resource.Loading -> {
_boardDataUiState.update { currentState ->
currentState.copy(isLoading = true)
}
}
}
}
}
}
GetLastBoardDataUseCase
class GetLastBoardDataUseCase @Inject constructor(
private val boardDataRepository: BoardDataRepository
) {
operator fun invoke(): Flow<Resource<BoardData>> = flow {
emit(Resource.Loading())
try {
emit(Resource.Success(boardDataRepository.getBoardList().first()))
} catch (e: Exception) {
emit(Resource.Failure(e.message.toString()))
}
}
}
VisionBoardNavigation
@Composable
fun VisionBoardNavigation(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = Screens.HomeScreen.route
) {
composable(Screens.HomeScreen.route) { navBackStack ->
val boardName = navBackStack.arguments?.getString("boardName")
val boardUId = navBackStack.arguments?.getInt("boardUId")
boardUId?.let { homeViewModel.getBoardSectionList(it) }
val homeUiState by homeViewModel.sectionList.collectAsState()
HomeScreen(boardName.toString(), homeUiState)
}
}
}
@Composable
fun HomeScreen(boardName: String = "Hey There", homeUiState: HomeScreenUIState) {
var showLoading by remember {
mutableStateOf(false)
}
LaunchedEffect(key1 = homeUiState.loading, block = {
showLoading = homeUiState.loading
})
if (showLoading) {
Dialog(
onDismissRequest = { },
DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(100.dp)
.background(White, shape = RoundedCornerShape(16.dp))
) {
CircularProgressIndicator()
}
}
}
} {
}
OUTPUT

You can check my solution which explains multiple recomposition and use of
LaunchedEffectin jetpack compose. https://stackoverflow.com/a/76969294/14972910In this case
showLoadingvariable isremeberedand set totrueinHomeScreencomposable and so that whenever theHomeScreenrecomposes then it will also recompose the dialog as theshowLoadingistrue.So you have to restrict
HomeScreenfor recomposition and you can useLaunchedEffectfor that in theNavHost.