androidkotlinandroid-navigationkotlinx.serialization

Issue with androidx.navigation library and slash sign


Issue description:

When I try to create custom navigation type and navigate to certain destination in my NavGraph, I get error, which states, that this certain destination cannot be found in the graph. After checking, some of items on list of adressess have street name for example Green Street 1 which doesn't cause any issue, but adressess with street name as Green Street 1/3 do. I suppose it might be related to the androidx.navigation library itself, as under the hood, navigation in this library works with URLS, which contain slashes between variables.

Actual outcome:

Application crashes after navigating to address with slash "/" sign

Expected outcome:

Application doesn't crash after navigation to adressess both with and without "/" sign in it.

Code:

@Serializable
data class Address(
    val city: String?,
    val companyId: Int,
    val country: String?,
    val gpsCoordinates: String?,
    val id: Int,
    val pointName: String? = null,
    val pointType: String,
    val postalCode: String?,
    val street: String?
)


val AddressType = object : NavType<Address?>(isNullableAllowed = true) {
    override fun get(bundle: Bundle, key: String): Address? {
        return bundle.getString(key)?.takeIf { it != "null" }
            ?.let { Json.decodeFromString<Address>(it) }
    }

    override fun parseValue(value: String): Address? {
        return if (value == "null") null else Json.decodeFromString<Address>(value)
    }

    override fun serializeAsValue(value: Address?): String {
        return Json.encodeToString(value)
    }

    override fun put(bundle: Bundle, key: String, value: Address?) {
        bundle.putString(key, Json.encodeToString(value))
    }
}

In my NavGraph everything looks correct, as I am able to navigate to destinations without street name containing "/" sign.


Solution

  • Thanks @ianhanniballake

    If someone would look for a solution to this issue for Compose Multiplatform:

    @OptIn(ExperimentalEncodingApi::class)
    val AddressType = object : NavType<Address?>(isNullableAllowed = true) {
        override fun get(bundle: Bundle, key: String): Address? {
            return bundle.getString(key)?.takeIf { it != "null" }
                ?.let { Json.decodeFromString(Base64.UrlSafe.decode(it).decodeToString()) }
        }
    
        override fun parseValue(value: String): Address? {
            return if (value == "null") null else Json.decodeFromString(Base64.UrlSafe.decode(value).decodeToString())
        }
    
        override fun serializeAsValue(value: Address?): String {
            return Base64.UrlSafe.encode(Json.encodeToString(value).encodeToByteArray())
        }
    
        override fun put(bundle: Bundle, key: String, value: Address?) {
            bundle.putString(key, Base64.UrlSafe.encode(Json.encodeToString(value).encodeToByteArray()))
        }
    }