Android Jetpack compose Scaffold content recomposition

150 Views Asked by At

I am making a simple music player app, I'm trying to learn jetpack compose. I want to make an overlay view that will show over all the other app screens, similar to floating action button. This view has a progress bar showing the audio playing progress. I have achieved this with the code bellow..

@Composable
fun AppNavHost(
    openAudioFile: (path: String) -> Unit,
    playPauseClick: () -> Unit,
    stopPlayingClick: () -> Unit,
    state: State<AppScreenState>
) {
    val audioFileState = state.value.audioFileState
    val snackBarHostState = remember { SnackbarHostState() }
    Scaffold(
        snackbarHost = {
            SnackbarHost(hostState = snackBarHostState)
        },
        floatingActionButton = {
            if (audioFileState != AudioFileState.IDLE && audioFileState != AudioFileState.STOPED)
                AppPlayerBar(
                    state.value,
                    playPauseClick = playPauseClick,
                    stopPlayingClick = stopPlayingClick
                )
        }
    ) { contentPadding ->
        val navController = rememberNavController()
        NavHost(
            navController = navController,
            startDestination = Screen.MusicFoldersScreen.route,
            modifier = Modifier.padding(contentPadding)
        ) {
            composable(
                route = Screen.MusicFoldersScreen.route + "?path={path}",
                arguments = listOf(navArgument(name = "path") {
                    type = NavType.StringType
                    defaultValue = ""
                })
            ) { backStackEntry ->
                val navArgs = backStackEntry.arguments
                var path = ""
                navArgs?.getString("path")?.let {
                    path = it
                }
                val musicViewModel = hiltViewModel<MusicFoldersViewModel>()
                if (path.isBlank()) {
                    musicViewModel.loadMusicFolders()
                } else {
                    musicViewModel.loadMusicFilesFromPath(path)
                }
                MusicFoldersScreen(
                    musicFolders = musicViewModel.musicFoldersState.collectAsState(
                        initial = emptyList()
                    )
                ) { newPath ->
                    if (newPath.endsWith(".mp3") || newPath.endsWith(".m4a")) {
                        openAudioFile(newPath)
                        return@MusicFoldersScreen
                    } else {
                        navController.navigate(Screen.MusicFoldersScreen.route + "?path=$newPath")
                    }
                }
            }
        }
    }
}

Another component in my app changes the state.audioFileProgress . The AudioFileState is a data class defined like this: data class AppScreenState(var audioFileState: AudioFileState, var audioFileProgress: Float)

The problem is that the Scaffold content (NavHost) is recomposed. I don't know why. It doesn't uses the state object

1

There are 1 best solutions below

0
Heixss On

Update: I resolved the problem by moving val audioFileState = state.value.audioFileState into floatingActionButton content like this:

    openAudioFile: (path: String) -> Unit,
    playPauseClick: () -> Unit,
    stopPlayingClick: () -> Unit,
    state: State<AppScreenState>
) {
    val snackBarHostState = remember { SnackbarHostState() }
    Scaffold(
        snackbarHost = {
            SnackbarHost(hostState = snackBarHostState)
        },
        floatingActionButton = {
            val audioFileState = state.value.audioFileState
            if (audioFileState != AudioFileState.IDLE && audioFileState != AudioFileState.STOPED)
                AppPlayerBar(
                    state.value,
                    playPauseClick = playPauseClick,
                    stopPlayingClick = stopPlayingClick
                )
        }
    )

Now only the floatingActionButton is recomposed.