kotlinandroid-jetpack-compose

Using Jetpack compose type safe navigation with custom data class


i write custom nav which will allow passing objects with screen so when navigate to the screen with task value works fine but when navigating to screen without task because i need task to be null the app crashes


object CustomNavType {

    val TaskType = object : NavType<Task?>(isNullableAllowed = true) {
        private val taskSerializer = Task.serializer()

        override fun get(bundle: Bundle, key: String): Task? {
            return bundle.getString(key)?.let { Json.decodeFromString(taskSerializer, it) }
        }

        override fun parseValue(value: String): Task? {
            return if (value == "null") null else Json.decodeFromString(taskSerializer, Uri.decode(value))
        }

        override fun put(bundle: Bundle, key: String, value: Task?) {
            bundle.putString(key, value?.let { Json.encodeToString(taskSerializer, it) } ?: "null")
        }

        override fun serializeAsValue(value: Task?): String {
            return value?.let { Uri.encode(Json.encodeToString(taskSerializer, it)) } ?: "null"
        }
    }
}
@Serializable
data class Task(
    val id: Int,
    var title: String,
    val description: String?,
    val completed: String,
    val color: String,
    var images: List<TaskImage>? = null,
    var isChecked: Boolean? = false
) {

    val cardColor: Color
        get() {
            return color.toColor()
        }

}
@Serializable
data class TaskImage(
    val id: Int,
    val title: String,
    @SerializedName("filename")
    val fileName: String,
    @SerializedName("mimetype")
    val mimeType: String,
    @SerializedName("taskid")
    val taskId: Int,
    @SerializedName("imageurl")
    val imageUrl: String,
)

and in navigation graph i am using it like this

 composable<TaskRoutes.AddTaskScreen>(
                typeMap = mapOf(
                    typeOf<Task?>() to CustomNavType.TaskType
                )
            ) { backStackEntry ->
                val args = backStackEntry.toRoute<TaskRoutes.AddTaskScreen>()
                AddTaskScreen(navController, sharedToDoViewModel, taskDetails = args.task)
            }

the app crash when call

 navController.navigate(TaskRoutes.AddTaskScreen)

but not crash when call it as

 navController.navigate(TaskRoutes.AddTaskScreen(task))

crash that i am getting

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.


Solution

  • I think you can try default values for routes,

    In your routes just try it,

    @Serializable
    sealed class TaskRoutes {
        
        @Serializable
        data class AddTaskScreen(val task: Task? = null) : TaskRoutes()  // Default is nullable task field
    
    }
    

    And call it,

    For null task:
    navController.navigate(TaskRoutes.AddTaskScreen())
    
    For non null:
    navController.navigate(TaskRoutes.AddTaskScreen(task))
    
    

    Now the error will not come i think so,

    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.