Why my viewModel function won't load data from JSON using retrofit? - android

In my application i'm using Navigation Compose. After implementing it, my viewModel's function getExercises() won't fetch the data. Why is that?
MainActivity:
class MainActivity : ComponentActivity() {
lateinit var navController: NavHostController
lateinit var viewModel: ExerciseViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GymEncV2Theme {
// A surface container using the 'background' color from the theme
navController = rememberNavController()
viewModel = ExerciseViewModel()
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
SetupNavGraph(navController = navController, viewModel = viewModel)
}
}
}
}
}
NavGraph:
#Composable
fun SetupNavGraph(navController: NavHostController, viewModel: ExerciseViewModel) {
NavHost(navController = navController, startDestination = Screen.Home.route) {
composable(
route = Screen.Home.route
) {
HomeScreen(navController = navController)
}
composable(
route = Screen.SampleExercise.route,
arguments = listOf(navArgument(SAMPLE_EXERCISE_SCREEN_KEY) {
type = NavType.StringType
})
) {
SampleExerciseScreen(navController = navController, viewModel = viewModel, muscleGroup = it.arguments?.getString(
SAMPLE_EXERCISE_SCREEN_KEY).toString())
}
}
}
ExerciseApi built with Retrofit:
interface ExerciseApi {
#GET("GymEnc_v2.JSON")
suspend fun getExercises() : List<Exercise>
companion object {
private var exerciseApi: ExerciseApi? = null
fun getInstance() : ExerciseApi {
if (exerciseApi == null) {
exerciseApi = Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ExerciseApi::class.java)
}
return exerciseApi!!
}
}
}
Repository Implementation:
class ExerciseRepositoryImpl : ExerciseRepository {
private val api = ExerciseApi.getInstance()
override suspend fun getExercises(): List<Exercise> {
return api.getExercises()
}
}
And finally the viewModel:
class ExerciseViewModel : ViewModel() {
private val repository = ExerciseRepositoryImpl()
var exerciseListResponse : List<Exercise> by mutableStateOf(arrayListOf())
var errorMessage: String by mutableStateOf("")
fun getExercises(): List<Exercise>{
viewModelScope.launch {
try {
val exerciseList = repository.getExercises()
exerciseListResponse = exerciseList
} catch (e: Exception) {
errorMessage = e.message.toString()
}
}
return exerciseListResponse
}
}
SampleExercisesScreen:
#Composable
fun SampleExerciseScreen(navController: NavController, muscleGroup: String, viewModel: ExerciseViewModel) {
val exerciseList = viewModel.getExercises().filter { it.muscle == muscleGroup }
Surface(modifier = Modifier.fillMaxSize(),
color = AppColors.mBackground) {
Column {
MyTopBar(navController = navController)
Text(text = muscleGroup,
style = MaterialTheme.typography.h3,
color = AppColors.mDetails,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center)
UserExercisesButton()
}
}
}
After using viewModel.getExercises() in SampleExercisesScreen, they simply won't load, leaving me with an empty list.

Related

GET request in retrofit in android is not working

I am trying to learn compose and retrofit and for that I am developing a very easy app, fetching jokes from a public API and showing them in a lazy list. But it is not working and I am not able to see any jokes. I am new to Kotlin and Jetpack compose. Please help me debug this.
I have a joke class
data class Joke(
val id: Int,.
val punchline: String,
val setup: String,
val type: String
)
This is the API I am GETing from:
https://official-joke-api.appspot.com/jokes/:id
This is the response:
{"type":"general","setup":"What did the fish say when it hit the wall?","punchline":"Dam.","id":1}
This is the retrofit api service:
const val BASE_URL = "https://official-joke-api.appspot.com/"
interface JokeRepository {
#GET("jokes/{id}")
suspend fun getJoke(#Path("id") id: String ) : Joke
companion object {
var apiService: JokeRepository? = null
fun getInstance(): JokeRepository {
if (apiService == null) {
apiService = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build().create(JokeRepository::class.java)
}
return apiService!!
}
}
}
This is the Jokes view model:
class JokeViewModel : ViewModel() {
private val _jokeList = mutableListOf<Joke>()
var errorMessage by mutableStateOf("")
val jokeList: List<Joke> get() = _jokeList
fun getJokeList() {
viewModelScope.launch {
val apiService = JokeRepository.getInstance()
try {
_jokeList.clear()
// for(i in 1..100) {
// var jokeWithId = apiService.getJoke(i.toString())
// _jokeList.add(jokeWithId)
// Log.d("DEBUGGG", jokeWithId.setup)
// }
var joke = apiService.getJoke("1")
_jokeList.add(joke)
}
catch (e: Exception) {
errorMessage = e.message.toString()
}
}
}
}
This is the Main Activity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val jokeViewModel = JokeViewModel()
super.onCreate(savedInstanceState)
setContent {
HasyamTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
JokeView(jvm = jokeViewModel)
}
}
}
}
}
This is the Joke Component and view
#Composable
fun JokeView(jvm: JokeViewModel) {
LaunchedEffect(Unit, block = {
jvm.getJokeList()
})
Text(text = jvm.errorMessage)
LazyColumn() {
items(jvm.jokeList) {
joke -> JokeComponent(joke)
}
}
}
#OptIn(ExperimentalMaterial3Api::class)
#Composable
fun JokeComponent(joke: Joke) {
var opened by remember { mutableStateOf(false)}
Column(
modifier = Modifier.padding(15.dp)
) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable { },
elevation = CardDefaults.cardElevation(
defaultElevation = 5.dp
),
onClick = { opened = !opened}
) {
Text(modifier = Modifier.padding(15.dp), text = joke.setup)
}
if (opened) {
Text(modifier = Modifier.padding(15.dp), text = joke.punchline)
}
}
}
Thank you so much
The issue here is that you are not using stateFlow. The screen is not recomposed so your LazyColumn is not recreated with the updated values.
ViewModel
class JokeViewModel : ViewModel() {
var errorMessage by mutableStateOf("")
private val _jokes = MutableStateFlow(emptyList<Joke>())
val jokes = _jokes.asStateFlow()
fun getJokeList() {
viewModelScope.launch {
val apiService = JokeRepository.getInstance()
try {
var jokes = apiService.getJoke("1")
_jokes.update { jokes }
} catch (e: Exception) {
errorMessage = e.message.toString()
}
}
}
}
Joke View
#Composable
fun JokeView(jvm: JokeViewModel) {
val jokes by jvm.jokes.collectAsState()
LaunchedEffect(Unit, block = {
jvm.getJokeList()
})
Text(text = jvm.errorMessage)
LazyColumn {
items(jokes) {
joke -> JokeComponent(joke)
}
}
}
You should read the following documentation about states : https://developer.android.com/jetpack/compose/state

how to Update my UI using android jetpack compose and retrofit with a new request data from retrofit

I have created an app using kotlin and android jetpack compose and dependency injection for creating my
retrofit and room datebase the problem is that I'm getting some data using retrofit from internet and showing them in my ui but when I want to send a request for the second time I get the information but
I don't know how to put them insted of existing list that I have .
It's like a movie app that I want to go to next page or load more data when the list ends
interface AppGameApi {
#GET("farsroid")
suspend fun getAppGameFromPage(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String,
#Query("page") page: String
): AppGame
#GET("farsroid")
suspend fun getAppGameFromSearch(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String = "search",
#Query("q") q: String = ""
): AppGame
#GET("farsroid")
suspend fun getAppGameFromDownload(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String = "download",
#Query("link") link: String = ""
): AppGameDownload
}
class AppGameRetrofitRepository #Inject constructor(private val api: AppGameApi) {
private val appGames = DataOrException<AppGame,Boolean,Exception>()
private val appGamesSearch = DataOrException<AppGame,Boolean,Exception>()
private val appGamesDownload = DataOrException<AppGameDownload,Boolean,Exception>()
suspend fun getAllAppGames(page:String,action:String):DataOrException<AppGame,Boolean,java.lang.Exception>{
try {
appGames.isLoading = true
appGames.data = api.getAppGameFromPage(page = page, action = action)
if (appGames.data!!.status == 200) appGames.isLoading = false
Log.d("Mr", "getAllAppGames: ${appGames.data!!.result[0]}")
}catch (exception:Exception){
appGames.e = exception
}
return appGames
}
suspend fun getAllAppGamesSearch(q:String):DataOrException<AppGame,Boolean,java.lang.Exception>{
try {
appGamesSearch.isLoading = true
appGamesSearch.data = api.getAppGameFromSearch(q = q)
if (appGamesSearch.data!!.status == 200) appGamesSearch.isLoading = false
}catch (exception:Exception){
appGamesSearch.e = exception
Log.d("Error", "getAllAppGames: ${appGamesSearch.e!!.localizedMessage} ")
}
return appGamesSearch
}
suspend fun getAllAppGamesDownload(link:String):DataOrException<AppGameDownload,Boolean,java.lang.Exception>{
try {
appGamesDownload.isLoading = true
appGamesDownload.data = api.getAppGameFromDownload(link = link)
if (appGamesDownload.data!!.status == 200) appGamesDownload.isLoading = false
}catch (exception:Exception){
appGamesDownload.e = exception
Log.d("Error", "getAllAppGames: ${appGamesDownload.e!!.localizedMessage} ")
}
return appGamesDownload
}
}
#HiltViewModel
class AppGameRetrofitViewModel #Inject constructor(private val repository: AppGameRetrofitRepository) :
ViewModel() {
var appGame: MutableState<DataOrException<AppGame, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
private val appGameSearch: MutableState<DataOrException<AppGame, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
private val appGameDownload: MutableState<DataOrException<AppGameDownload, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
init {
getAllAppGames("1","app")
}
fun getAllAppGames(
page: String,
action: String
): DataOrException<AppGame, Boolean, Exception> {
viewModelScope.launch {
appGame.value.isLoading = true
appGame.value = repository.getAllAppGames(page = page, action = action)
if (appGame.value.data!!.status == 200) appGame.value.isLoading = false
}
return appGame.value
}
private fun getAllAppGamesSearch(q: String = "") {
viewModelScope.launch {
appGameSearch.value.isLoading = true
appGameSearch.value = repository.getAllAppGamesSearch(q = q)
if (appGameSearch.value.data!!.status == 200) appGameSearch.value.isLoading = false
}
}
private fun getAllAppGamesDownload(link: String = "") {
viewModelScope.launch {
appGameDownload.value.isLoading = true
appGameDownload.value = repository.getAllAppGamesDownload(link = link)
if (appGameDownload.value.data!!.status == 200) appGameDownload.value.isLoading = false
}
}
}
I have tried these and my mainActivity looks like this
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Android_Complete_TemplateTheme {
val appGameViewModelRoomDatabase by viewModels<RoomDatabaseViewModel>()
val appGameViewModelRetrofit by viewModels<AppGameRetrofitViewModel>()
val navController = rememberNavController()
val pageCounter = remember {
mutableStateOf("1")
}
val pageAction = remember {
mutableStateOf("game")
}
FarsroidNavigationSystem(
roomDatabaseViewModel = appGameViewModelRoomDatabase,
appGameRetrofitViewModel = appGameViewModelRetrofit,
navController = navController,
) {
if (appGameViewModelRetrofit.appGame.value.isLoading == true) {
AppGame(
status = 200,
result = listOf()
)
} else {
appGameViewModelRetrofit.getAllAppGames(
pageCounter.value,
pageAction.value
).data!!
}
}
pageCounter.value= pageCounter.value+1
}
}
}
}
#Composable
fun FarsroidNavigationSystem(
roomDatabaseViewModel: RoomDatabaseViewModel,
appGameRetrofitViewModel: AppGameRetrofitViewModel,
navController: NavHostController,
onClicked: () -> AppGame
) {
NavHost(
navController = navController,
startDestination = Screens.HomeScreen.name
) {
composable(route = Screens.HomeScreen.name) {
HomeScreen(
retrofitViewModel = appGameRetrofitViewModel,
navController = navController
){
onClicked()
}
}
composable(route = Screens.DetailScreen.name) {
DetailScreen(
roomDatabaseViewModel = roomDatabaseViewModel,
navController = navController
)
}
}
}
#Composable
fun HomeScreen(
retrofitViewModel: AppGameRetrofitViewModel,
navController: NavHostController,
onClicked: () -> AppGame
) {
Scaffold(
modifier = Modifier
.fillMaxSize(),
backgroundColor = Color.White,
contentColor = Color.DarkGray
) { paddingValues ->
Spacer(modifier = Modifier.padding(paddingValues))
if (onClicked().status != 200)
CircularProgressIndicator(modifier = Modifier.fillMaxSize(), color = Color.Red)
else
LazyColumn {
items(onClicked().result) {
ItemCard(resultAppGame = it)
}
}
Button(onClick = {
onClicked()
}) {
Text("LoadMore")
}
}
}
#Composable
fun ItemCard(
resultAppGame: ResultAppGame,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
shape = CutCornerShape(10.dp),
backgroundColor = Color.White,
contentColor = Color.DarkGray,
elevation = 10.dp
) {
Column(
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
modifier = Modifier
.size(150.dp)
.padding(20.dp),
elevation = 10.dp,
shape = CircleShape,
backgroundColor = Color.White,
border = BorderStroke(width = 0.5.dp, Color.LightGray)
) {
Image(
painter = rememberAsyncImagePainter(
model = resultAppGame.pic),
contentDescription = resultAppGame.pic,
contentScale = ContentScale.Fit
)
}
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.title, textAlign = TextAlign.Right)
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.description, textAlign = TextAlign.Right)
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.link)
}
}
}

How to use DataStore in jetpack compose when splash screen is running?

I have tried by my self, but im getting for close and no error message detected in my ANDROID STUDIO IDE, please help me to solve this. i really appreciate who help me for this. thank you. sorry i am not experience in android dev
MyDataStoreRepoInterface
interface DataStoreRepo {
suspend fun putString(key:String,value:String)
suspend fun putBoolean(key:String,value:Boolean)
suspend fun getString(key: String):String?
suspend fun clearPReferences(key: String)
}
**MyDataStoreRepoImpl**
private val Context.dataStore : DataStore<Preferences> by preferencesDataStore(name=DATASTORE_NAME)
class DataStoreRepoImpl #Inject constructor(
private val context: Context
): DataStoreRepo {
override suspend fun putString(key: String, value: String) {
val prefereneKay = stringPreferencesKey(key)
context.dataStore.edit {
it[prefereneKay] = value
}
}
override suspend fun putBoolean(key: String, value: Boolean) {
val prefernceKey = booleanPreferencesKey(key)
context.dataStore.edit {
it[prefernceKey] = value
}
}
override suspend fun getString(key: String): String? {
return try {
val preferenceKey = stringPreferencesKey(key)
val preference = context.dataStore.data.first()
preference[preferenceKey]
}catch (e:Exception){
e.printStackTrace()
null
}
}
override suspend fun clearPReferences(key: String) {
val preferenceKey = stringPreferencesKey(key)
context.dataStore.edit {
if (it.contains(preferenceKey)){
it.remove(preferenceKey)
}
}
}
}
My Dependency Module
#Module
#InstallIn(SingletonComponent::class)
object AppModule {
#Provides
#Singleton
fun provideEpodApi(): ApiClient {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiClient::class.java)
}
#Provides
#Singleton
fun providesDatstoreRepo(
#ApplicationContext context: Context
): DataStoreRepo = DataStoreRepoImpl(context)
#Provides
#Singleton
fun provideCoinRepository(api: ApiClient): LoginRepository {
return LoginRepositoryImpl(api)
}
}
LoginViewModel
#HiltViewModel
class LoginViewModel #Inject constructor(
private val useCase: LoginUseCase,
private val dataStoreRepository:DataStoreRepo
) : ViewModel() {
var state by mutableStateOf(LoginState())
val email = mutableStateOf("")
val password = mutableStateOf("")
fun login(username: String, password: String) = viewModelScope.launch {
state = state.copy(isLoading = true)
val loginDeferred =
async { useCase.execute(loginRequest = LoginRequest(username, password)) }
when (val result = loginDeferred.await()) {
is Resource.Success -> {
state = state.copy(
login = result.data,
error = null,
isLoading = false
)
}
is Resource.Error ->
state = state.copy(
isLoading = false,
error = result.message,
login = null
)
else -> Unit
}
}
fun storeUserName(value:String) = runBlocking {
dataStoreRepository.putString(USER_NAME,value)
}
fun getUserName():String = runBlocking {
dataStoreRepository.getString(USER_NAME)!!
}
fun clearPreferences(key:String) = runBlocking {
dataStoreRepository.clearPReferences(key)
}
LoginScreen
Button(onClick = {
viewModel.login(username, password)
viewModel.storeUserName(username)
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
enabled = isFormValid,
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = Blue500)
) {
Text(
text = "Login",
fontFamily = Poppins,
fontWeight = FontWeight.Bold,
color = Color.White,
fontSize = 16.sp
)
}
SplashScreen
#Composable
fun SplashScreen(
navController: NavController,
viwmodel:LoginViewModel = hiltViewModel()
) {
var startAnimation by remember { mutableStateOf(false) }
val scaleAnimation by animateFloatAsState(
targetValue = if (startAnimation) 0.7f else 0f,
animationSpec = tween(
durationMillis = 800,
easing = {
OvershootInterpolator(4f).getInterpolation(it)
})
)
val loginState = viwmodel.getUserName()
when(loginState){
"USER_NAME" ->{
navController.popBackStack()
navController.navigate("login_screen")
}
else ->{
navController.popBackStack()
navController.navigate("onboarding_screen")
}
LaunchedEffect(key1 = loginState ){
startAnimation = true
delay(3000L)
}
}
Splash(scaleAnimation)
}

IllegalStateException with snapshots when using Dispatchers.IO and Dispatchers.Main in ViewModel

I want to show a spinning progress bar while shopping list items are being retrieved from the database in the ViewModel and then hide it when the data has been loaded, but the code below throws the following IllegalStateException. How can I fix it?:
java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied
Composable
#Composable
fun ShoppingListScreen(
navController: NavHostController,
shoppingListScreenViewModel: ShoppingListScreenViewModel,
sharedViewModel: SharedViewModel
) {
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val allItems = shoppingListScreenViewModel.shoppingListItemsState.value?.collectAsLazyPagingItems()
val showProgressBar = shoppingListScreenViewModel.loading.value
...
Box {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(screenHeight)
) {
if (allItems?.itemCount == 0) {
item { Text("You don't have any items in this shopping list.") }
}
items(
items = allItems!!,
key = { item ->
item.id
}
) { item ->
ShoppingListScreenItem(
navController = navController,
item = item,
sharedViewModel = sharedViewModel
) { isChecked ->
scope.launch {
shoppingListScreenViewModel.changeItemChecked(item!!, isChecked)
}
}
}
item { Spacer(modifier = Modifier.padding(screenHeight - (screenHeight - 70.dp))) }
}
ConditionalCircularProgressBar(isDisplayed = showProgressBar)
}
...
}
ViewModel
#HiltViewModel
class ShoppingListScreenViewModel #Inject constructor(
private val getAllShoppingListItemsUseCase: GetAllShoppingListItemsUseCase
) : ViewModel() {
private val _shoppingListItemsState = mutableStateOf<Flow<PagingData<ShoppingListItem>>?>(null)
val shoppingListItemsState: State<Flow<PagingData<ShoppingListItem>>?> get() = _shoppingListItemsState
val loading = mutableStateOf(false)
init {
loading.value = true
getAllShoppingListItemsFromDb()
}
private fun getAllShoppingListItemsFromDb() {
viewModelScope.launch(Dispatchers.IO){
_shoppingListItemsState.value = getAllShoppingListItemsUseCase().distinctUntilChanged()
withContext(Dispatchers.Main) {
loading.value = false
}
}
}

How to pass Arguments between Nested Navigation Graph Jet Compose

I want to pass {id} from ListScreen to DetailScreen. In ListScreen, when a click event is occured, I start navigate to DetailScreen like this.
navController.navigate(
route = AppDestination.UserProfile.passId(
friendId = it.friendId
)
)
In DetailScreen, I get that friendId through constructor like this.
#Composable
fun UserProfileScreen(
navController: NavController,
friendId: Long,
) {
UserProfileView(
navController = navController,
friendId = friendId
)
}
In my app, I just manage navigation flow with 3 graphs. Like RootGraph, AuthGraph and HomeGraph. Following is the navigation codes.
object Routes {
const val AUTH_ROUTE = "auth"
const val HOME_ROUTE = "home"
const val ROOT_ROUTE = "root"
}
object ArgsConstants{
const val USER_PROFILE_KEY = "id"
}
sealed class AppDestination(val route: String) {
//user
object UserProfile : AppDestination(route = "user_profile_screen/{${ArgsConstants.USER_PROFILE_KEY}}"){
fun passId(friendId : Long): String{
return this.route.replace(
oldValue = "{${ArgsConstants.USER_PROFILE_KEY}}",
newValue = friendId.toString()
)
}
}
}
This is my RootGraph.
#Composable
fun RootNavGraph(
navController: NavHostController
) {
NavHost(
navController = navController,
startDestination = AppDestination.Branding.route,
route = Routes.ROOT_ROUTE
) {
composable(route = AppDestination.Branding.route) {
BrandingScreen(navController = navController)
}
authNavGraph(navController = navController)
homeNavGraph(navController = navController)
}
}
This is my AuthGraph.
fun NavGraphBuilder.authNavGraph(
navController: NavHostController
) {
navigation(
startDestination = AppDestination.Language.route,
route = Routes.AUTH_ROUTE
) {
composable(route = AppDestination.Language.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
LanguageScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.Login.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
LoginScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.Signup.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
SignupScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedAccount.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedAccountScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.NoAccount.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
NoAccountScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedMethod.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedMethodScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedOtp.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedOtpScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedQuestion.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedQuestionScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.TwoFactor.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
TwoFactorScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.PasswordReset.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
PasswordResetScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.SuccessReset.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
SuccessResetScreen(navController = navController, vm = authViewModel)
}
}
}
This is my HomeGraph.
fun NavGraphBuilder.homeNavGraph(
navController: NavHostController
) {
navigation(
startDestination = AppDestination.Home.route,
route = Routes.HOME_ROUTE
) {
//user
composable(route = AppDestination.UserProfile.route + "/{${ArgsConstants.USER_PROFILE_KEY}}",
arguments = listOf(
navArgument(
name = ArgsConstants.USER_PROFILE_KEY,
) {
type = NavType.LongType
}
)) {
Timber.tag("ahahah").d(it.arguments?.getLong(ArgsConstants.USER_PROFILE_KEY).toString())
UserProfileScreen(
navController = navController,
friendId = it.arguments?.getLong(ArgsConstants.USER_PROFILE_KEY) ?: -1L
)
}
}
}
This is my error when navigate route is launch.
java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/user_profile_screen/1084 } cannot be found in the navigation graph NavGraph(0x78dcd1ef) route=root startDestination={Destination(0xf2da2703) route=branding_screen}
I have implemented navigation arguments in other projects but in this project, I manage 3 graphs. I think my failure is because of this. I tried other ways like shared with saveStateHandle in ViewModel. and also fail. Please help me. I stuck in this a week.

Categories

Resources