Search code examples
androidkotlinandroid-jetpack-composeandroid-viewmodel

Getting the ViewModel in to display information in Jetpack Compose


So I am a bit stuck with how to create the ViewModel and pass it into my composable so that I can use the Data Class models to display on the textView.

Here's the code

MainActivity

private const val TAG = "MainActivity"
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val viewModel: PokemonListViewModel by viewModels()

        setContent {
//            val pokemon = viewModel.pokemon.value
          PokeDexComposeTheme {
              Surface(
                  modifier = Modifier.fillMaxSize(),
                  color = Color.Cyan) {

                PokemonListScreen()
              }
          }

        }
    }
}


@Composable
fun PokemonListScreen(viewModel: PokemonListViewModel){
 //Tried this method as well
 val pokemon by viewModel.pokemonLiveData.observeAsState("")
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp),
            verticalArrangement = Arrangement.Top,
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            ClickableText(
                text = AnnotatedString(),
                onClick = {offset ->
                    Log.d(TAG, "PokemonListScreen: clicked")
                },
                )

            Divider(
                Modifier.padding(start = 24.dp, end = 24.dp),
                color = Color.Black,
                thickness = 2.dp
            )
        }
    }



@Composable
fun PokemonDetails(){
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(top = 16.dp),
        verticalArrangement = Arrangement.Top,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
           fontSize = 25.sp,
            text = "NAME: "
        )
        Text(
            fontSize = 50.sp,
            text = "NameModel"
        )
        Divider(
            modifier = Modifier.padding(start = 24.dp, end = 24.dp),
            color = Color.Black,
            thickness = 1.dp
        )
        Text(
            modifier = Modifier.padding(8.dp),
            fontSize = 25.sp,
            text = "HEIGHT: "
        )
        Text(
            fontSize = 50.sp,
            text = "HeightModel"
        )
        Divider(
            modifier = Modifier.padding(start = 24.dp, end = 24.dp),
            color = Color.Black,
            thickness = 1.dp
        )
        Text(
            modifier = Modifier.padding(8.dp),
            fontSize = 25.sp,
            text = "WEIGHT: "
        )
        Text(
            fontSize = 50.sp,
            text = "WeightModel"
        )
        Divider(
            modifier = Modifier.padding(start = 24.dp, end = 24.dp),
            color = Color.Black,
            thickness = 1.dp
        )

    }
}

ViewModel

class PokemonListViewModel: ViewModel() {
    private val repository = PokemonRepository(PokemonApplication.pokemonListDatabase.pokemonDao)




init {
    fetchPokemonNames()
}


    private fun fetchPokemonNames(){
        viewModelScope.launch {
            val fetchPokeListEntity = repository.getAllPokemonNames()
                pokemon.value = fetchPokeListEntity
        }
    }


}

I am pretty new to Jetpack Compose, so my mindset was applying the viewModels the same way I would with regular XML layouts. Any help will be appreciated.


Solution

  • So I picked up some courses on Udemy, and StateFlow was the method used to replace MutableLiveData.

    class PokemonListViewModel: ViewModel() {
        private val repository = PokemonRepository(PokemonApplication.pokemonListDatabase.pokemonDao)
    
        private val _pokemonStateData = MutableStateFlow<List<PokeListEntity>?>(emptyList())
        val pokemonStateData = _pokemonStateData.asStateFlow()
    
    
        init {
            fetchPokemonNames()
        }
    
    
        fun fetchPokemonNames(){
            viewModelScope.launch {
                val fetchPokeListEntity = repository.getAllPokemonNames()
                _pokemonStateData.value = fetchPokeListEntity
            }
        }
    
    
    } 
    

    All I had to do was to use StateFlow and set up the ViewModel inside the Composeable properly. And it ended up working perfectly.

    @Composable
    fun PokemonListPage(
        pokemonViewModel: PokemonListViewModel = viewModel(), //<- adding viewModel as a parameter 
        navController: NavController){
    
        val pokeList = pokemonViewModel.pokemonStateData.collectAsState().value //<- creating a variable for the StateFlow variable
    
        Surface(
            modifier = Modifier
                .fillMaxHeight()
                .fillMaxWidth(),
        ) {
            Scaffold(topBar =
            {
                TopAppBar(
                    backgroundColor = Color.DarkGray,
                    elevation = 0.dp,
                ) {
                    Row(modifier = Modifier
                        .fillMaxWidth(),
                        horizontalArrangement = Arrangement.Center
                    ){
                        Text(
                            text = "POKEDEX",
                            fontWeight = FontWeight.Bold,
                            fontSize = 25.sp,
                            color = Color.Magenta
                        )
                    }
                }
            }, backgroundColor = Color.DarkGray){
                PokemonCards(pokemons = pokeList!!, navController = navController) //<- setting that variable to another composable which is leveraging the info from the viewModel 
            }
    

    enter image description here