Status Update
Comments
jb...@google.com <jb...@google.com>
il...@google.com <il...@google.com> #2
Could you please provide a minimal sample that reproduces this issue?
ed...@gmail.com <ed...@gmail.com> #3
Yes, of course
@Composable
private fun DemoNavHost() {
val controller = rememberNavController()
NavHost(
navController = controller,
startDestination = "mainRoute",
modifier = Modifier.fillMaxSize()
) {
composable("mainRoute") {
Surface() {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Button(
onClick = {
controller.navigate("demoDialog")
controller.navigate("demoDialog") // Simulate a quick click by the user
}
) {
Text(text = "show dialog")
}
}
}
}
dialog("demoDialog") {
val context = LocalContext.current
val lifecycle = LocalLifecycleOwner.current
Surface() {
Column() {
Text(text = "I'm demo dialog")
Button(
onClick = {
Toast
.makeText(
context,
"${lifecycle.lifecycle.currentState}",
Toast.LENGTH_SHORT
)
.show()
}
) {
Text(text = "check lifecycle")
}
Button(onClick = controller::popBackStack) {
Text(text = "close")
}
}
}
}
}
}
Steps:
Step 1: Click the show dialog
button on mainRoute
Step 2: Because 2 pop-up windows pop up, we close the top one
Step 3: Click the check lifecycle
button on the pop-up window, you can see STARTED
instead of RESUMED
I have also checked the cause, which is consistent with the description in my question.
il...@google.com <il...@google.com> #4
In fact, I found another problem. When the tester frequently clicks the button, the button event is to display a Dialog
, Dialog
is set to be destroyed by external click, so Dialog
is always displayed and destroyed
Interesting thing, because it may be too fast, causing DialogHost
to not notice that Dialog
appears and disappears, but it has actually joined NavController#_visibleEntries
But because NavHost#DialogHost
did not process DisposableEffect
, it will not execute dialogNavigator#onTransitionComplete
, so it will not be removed from NavController#_visibleEntries
, and a NavBackStackEntry
leak occurs
The reason may be that the pop-up window appears and disappears within one frame
cl...@google.com <cl...@google.com>
ap...@google.com <ap...@google.com> #5
Hi, can you please file a separate bug for the issue you see in
On initial bug - when multiple dialogs are open at the same time and the top one is dismissed, the second dialog in backstack is marked as transitioning to hold it in STARTED state until the top dialog has completed transitioning. But the second dialog was not marked as complete when composed so it stays in STARTED state instead of moving to expected RESUMED state.
cl...@google.com <cl...@google.com> #6
Thank you for your answer, I will open a separate post to ask a separate question;
ed...@gmail.com <ed...@gmail.com> #7
Thanks for filing the new bug! I was thinking a separate bug for the issue you see in commment#4 with NavBackStackEntry
possibly leaking. I'm gonna update the new bug's description to match that.
pr...@google.com <pr...@google.com> #8
Fixed internally and will be available in navigation 2.7.2
.
je...@gmail.com <je...@gmail.com> #9
Branch: androidx-main
commit b624e50960eb6601efe2cd3f5d81b95a12ff56f2
Author: Clara Fok <clarafok@google.com>
Date: Thu Jun 22 14:11:43 2023
Fix Dialog not marked complete
When multiple dialogs are open at the same time and the top one is dismissed, the second dialog in backstack is marked as transitioning to hold it in STARTED state until the top dialog has completed transitioning. But the second dialog was never marked as complete so it stays in STARTED state instead of moving to expected RESUMED state.
Now we make sure to mark Dialogs as complete when Dialog has been commposed.
Test: ./gradlew navigation:navigation-compose:cC
Bug: 286371387
Change-Id: I48da82d4c0db3fecd40b4357b152e807078066c6
M navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/DialogNavigatorTest.kt
M navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigator.kt
cl...@google.com <cl...@google.com> #10
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.navigation:navigation-compose:2.7.2
cl...@google.com <cl...@google.com> #11
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.navigation:navigation-compose:2.8.0-alpha01
ga...@gmail.com <ga...@gmail.com> #12
I'm also having this issue. I have created a repo for showcasing this:
In there you will find another case with a Parcelable object. In my case is quite strange since the logcat shows this error:
Process: com.bobbyesp.navigationbugreport, PID: 23169
kotlinx.serialization.SerializationException: Serializer for class 'Companion' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:278)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source:1)
at androidx.navigation.NavGraph.setStartDestination(NavGraph.kt:404)
cl...@google.com <cl...@google.com> #13
Re
But based on your source code, it is your startDestination in song
arg for your SongInformationPage
.
With safe args, you can conveniently pass in starting arguments by passing in a class instance. The arguments will automatically be available within the starting composable.
This means your nested graph should be
navigation<UtilitiesNavigator>(
startDestination = SongInformationPage(song = ...),
)
If your startDestination does not contain arguments, then you can pass in either:
@Serializable
object MyDestination
startDestination = MyDestination
--- OR ---
@Serializable
class MyDestination
startDestination = MyDestination::class
If you have further questions, please file a separate bug so it is easier for other users with the same question to locate the answer.
ga...@gmail.com <ga...@gmail.com> #14
du...@matechmobile.com <du...@matechmobile.com> #15
here is my code for you guys to look around:
fun setNavController(mNavController: NavController) {
this.navController = mNavController
navController.graph = navController.createGraph(startDestination = nav_routes.manual_add_otp_data) {
fragment<AddOtpManualFragment, AddOtpData>(
typeMap = mapOf(typeOf<AddOtpData>() to getCustomParametersType<AddOtpData>())
) {
label = nav_routes.manual_add_otp_data
}
}
}
--------
private inline fun <reified T : Parcelable> getCustomParametersType(nullable: Boolean = false) =
object : NavType<T>(
isNullableAllowed = nullable
) {
override fun put(bundle: Bundle, key: String, value: T) {
// Handle null case if the type is nullable
bundle.putParcelable(key, value)
}
override fun get(bundle: Bundle, key: String): T? {
// Return null if the value is nullable and not present
return if (isNullableAllowed) {
bundle.getParcelable(key)
} else {
bundle.getParcelable(key)
?: throw IllegalArgumentException("No value present for non-nullable type")
}
}
override fun parseValue(value: String): T {
// Decode and deserialize the string into the object
return Json.decodeFromString(value)
}
override fun serializeAsValue(value: T): String {
// Encode the object into a JSON string and Uri encode it
return Uri.encode(Json.encodeToString(value))
}
}
---------
@Serializable
@Parcelize
data class AddOtpData(val otpAuthDB: OtpAuthDB) : Parcelable
that all, thanks
Description
Version used: 2.8.0-alpha08
Devices/Android versions reproduced on: Pixel 6a (Android 14)
Getting the custom arg in a ViewModel when using just serializables instead of parcelables with this NavType:
val bookType = object : NavType<Book>(isNullableAllowed = false) {
override fun get(bundle: Bundle, key: String): Book? {
return bundle.getString(key)?.let { Json.decodeFromString<Book>(it) }
}
override fun parseValue(value: String) = Json.decodeFromString<Book>(value)
override fun serializeAsValue(value: Book): String = Json.encodeToString(value)
override fun put(bundle: Bundle, key: String, value: Book) {
bundle.putString(key, Json.encodeToString(value))
}
}
It works well if I get the value from the NavBackStackEntry but if I do this in the ViewModel:
val bookDetail = savedStateHandle.toRoute<BookDetail>()
I get this error when navigating to the detail:
java.lang.ClassCastException: java.lang.String cannot be cast to com.example.composenavigation.typesafety.Book
You can see an example in:
The navigation is in the file: TypeSafetyNavigation.kt
Thanks in advance!