'Composables can only be invoked from the context of a composable context

I'm building an application jetpack compose , after fetch some data from online source , i want to pass an id to as extras to the next screen so that i can call the next request api , but i'm facing two issues , the first issue is that showing me an error that composables can only be invoked from a composable context and the second issue is that i'm not sure wether i'm writing the correct code for calling the next screen , i appreciate any help , Thank you .

  • This is my code
   val lazyPopularMoviesItems = movies.collectAsLazyPagingItems()
    LazyVerticalGrid(cells = GridCells.Fixed(2)) {
        items(lazyPopularMoviesItems.itemCount) { index ->
            lazyPopularMoviesItems[index]?.let {
                Card(elevation = 8.dp, modifier = Modifier
                    .height(200.dp)
                    .padding(10.dp)
                    .clickable {
                        // This is the function i want to call and pass extras with it 
                        DetailsScreen(movieViewModel = movieViewModel, movieId = it.id)
                    }
                    .clip(RoundedCornerShape(8.dp))) {
                    Column {
                        Image(
                            painter = rememberImagePainter("http://image.tmdb.org/t/p/w500/" + it.backdrop_path),
                            contentDescription = null,
                            contentScale = ContentScale.Crop,
                            modifier = Modifier.height(150.dp)
                        )
                        Text(
                            modifier = Modifier
                                .height(50.dp)
                                .padding(3.dp)
                                .fillMaxWidth(),
                            text = it.title,
                            fontSize = 15.sp,
                            overflow = TextOverflow.Ellipsis,
                            maxLines = 1,
                            textAlign = TextAlign.Center,
                            color = androidx.compose.ui.graphics.Color.Black
                        )
                    }
                }
            }
        }
    }
  • MainActivity Code
 @AndroidEntryPoint
class MainActivity : ComponentActivity() {
    private val movieViewModel : MovieViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            val navController = rememberNavController()
            Scaffold(
             backgroundColor = Color.Blue.copy(0.1f),
             topBar = { TopAppBar(title = {Text(text = "Movie Flex")}, backgroundColor = Color.White, elevation = 10.dp)},
             bottomBar = {
                  val items = listOf(
                      BarItems.Popular,
                      BarItems.Playing,
                      BarItems.Top,
                      BarItems.Upcoming
                  )
                 BottomNavigation(backgroundColor = Color.Gray) {
                     items.forEach { item ->
                         BottomNavigationItem(
                             icon = { Icon(painter = painterResource(id = item.icon), contentDescription = item.title)},
                             label = { Text(text = item.title)},
                             selectedContentColor = Color.White,
                             alwaysShowLabel = true,
                             selected = false,
                             unselectedContentColor = Color.White.copy(0.5f),
                             onClick = {
                                 navController.navigate(item.route){
                                     navController.graph.startDestinationRoute?.let { route ->
                                         popUpTo(route) {
                                             saveState = true
                                         }
                                         // Avoid multiple copies of the same destination when
                                         // reselecting the same item
                                         launchSingleTop = true
                                         // Restore state when reselecting a previously selected item
                                         restoreState = true
                                     }
                                 }
                             })
                     }
                 }
             },
             content = {
                       ScreenNavigation(navController,movieViewModel)
             },

            )
        }
    }
}

@OptIn(ExperimentalCoilApi::class)
@Composable
fun ScreenNavigation(navController: NavHostController,movieViewModel: MovieViewModel){
    NavHost(navController = navController, startDestination  = BarItems.Popular.route){
        composable(route = BarItems.Popular.route){
            PopularScreen(movies = movieViewModel.getPopular(), movieViewModel = movieViewModel)
        }
        composable(route = BarItems.Playing.route){
            PlayingScreen(movies = movieViewModel.getPlaying())
        }
        composable(route = BarItems.Top.route){
            TopRatedScreen(movies = movieViewModel.getTopRated())
        }
        composable(route = BarItems.Upcoming.route){
            UpcomingScreen(movies = movieViewModel.getUpcoming())
        }

    }
}
  • Navigation Routing
 sealed  class BarItems(var route : String , var icon : Int , var title : String) {
    object Popular : BarItems("popular", R.drawable.ic_baseline_remove_red_eye_24,"Popular")
    object Playing : BarItems("playing",R.drawable.ic_baseline_remove_red_eye_24,"Playing")
    object Top : BarItems("top",R.drawable.ic_baseline_remove_red_eye_24,"Top")
    object Upcoming : BarItems("upcoming",R.drawable.ic_baseline_remove_red_eye_24,"Upcoming")
}


Solution 1:[1]

As you've pointed out, we'll need two things:

  1. Handle the navigation. You can use navigation-compose. Have a look at the documentation
  2. Trigger the navigation with either a LaunchedEffect or by launching a coroutine.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Stephen Vinouze