Status Update
Comments
jb...@google.com <jb...@google.com>
il...@google.com <il...@google.com> #2
Can you attach a sample project that reproduces your issue?
ed...@gmail.com <ed...@gmail.com> #3
I'm experiencing this issue in a commercial non-open source project so I'd have to provide extracted code fragments. The menu file for instance looks similar to this:
<menu>
<item
android:id="@+id/destination_one" />
<item
android:id="@+id/destination_two" />
<item
android:id="@+id/destination_three" />
<item
android:id="@+id/destination_four" />
</menu>
The menu item ids match the top level destination ids as for instance destination_one as required by the NavigationUI library.
The xml layout file of the main activity (there is only one activity) looks pretty much like this:
<androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.constraintlayout.widget.ConstraintLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/main_navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/navigation_host_fragment"
app:menu="@menu/main_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
The main_navigation
is the first navigation graph I posted in the original post. The behavior I described above only affects the first bottomNavigation item which corresponds to the top level navGraph's startDestination.
il...@google.com <il...@google.com> #4
Yeah, what we're looking for is a full project (i.e., take a brand new project in Android Studio, put your few bits of code in, and make sure your problem reproduces) as there are a lot of little pieces that can make a difference here.
cl...@google.com <cl...@google.com>
ap...@google.com <ap...@google.com> #5
Of course the logic of my project is more sophisticated but this reproduces the issue quite well. If you click the first BottomNavigation item N times you need N+1 system back navigation triggers to leave the app.
cl...@google.com <cl...@google.com> #6
So first, we plan to get rid of these APIs in the future. The only behavior for NavigationUI will be to always save and restore the state of the back stack. Luckily, NavigationUI is purposely built only on publicly available APIs so you could always copy our code and make your custom adjustments for whatever your desired behavior is.
The source of the bug is
We need to add a fix to ensure we take into account the proper destination on our side, but as I mentioned those APIs will go away in the future. So if you wanted to proactively create your own API, you could make your API navigate directly to the start destination instead of the graph. That would allow you to not wait on our release and ensure you always have your desired behavior going forward.
ed...@gmail.com <ed...@gmail.com> #7
Thanks a lot for your help! I basically removed the first embedded graph by moving the code directly into the topmost navGraph and as you said, navigate directly to the start destination. As far as I can tell, it seems to work now.
pr...@google.com <pr...@google.com> #8
Branch: androidx-main
commit 5624b7cefcfe5e0abb01f1063b040e5f2f135b75
Author: Clara Fok <clarafok@google.com>
Date: Wed Nov 30 16:47:38 2022
Clean up launchSingleTop logic
Basic refactoring in preparation for fix to
Test: ./gradlew navigation:navigation-runtime:cC
Bug: 253256629
Change-Id: Ib65764c345451d8be4613f6e3d278cc1a170091e
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
je...@gmail.com <je...@gmail.com> #9
Branch: androidx-main
commit f433d5458950a632900f8a2685ce6eab27272f8c
Author: Clara Fok <clarafok@google.com>
Date: Thu Dec 01 15:52:28 2022
Fix BottomNavView launchSingleTop with NavGraph
NavController previously did not apply launchSingleTop when user repeatedly navigates to the starting destination of a Menu when this starting destination is a NavGraph. This results in the destination being added mulitple times to backstack.
Now NavController checks if the destination is a NavGraph and if so, adds all destinations from the node to its final startDestination (i.e. nested nav graphs) to singleTop.
NavController backstack and Navigator backstacks entries are replaced accordingly upon singleTop navigations.
Test: ./gradlew navigation:navigation-runtime:cC
Bug: 253256629
Relnote: singleTop now works with NavGraph such that if the top destination of the backstack is a NavGraph's startDestination, all destinations starting from original destination to its startDestination will only be added to the top of the backstack once.
Change-Id: Id4bea16aff3dd776826fc6d746475e293eb64b0e
M navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
M navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
cl...@google.com <cl...@google.com> #10
This has been fixed internally and will be available in Navigation 2.6.0-alpha05
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-common:2.6.0-alpha05
androidx.navigation:navigation-runtime:2.6.0-alpha05
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
[Deleted User] <[Deleted User]> #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!