Аргумент навигации с @Parcelize перестал компилироваться после добавления поля
Экран деталей получает свою модель как аргумент навигации через Safe Args. Всё компилировалось и работало, пока в модель не добавили поле createdAt. Теперь сборка падает на модельном классе с ошибкой: Type is not directly supported by 'Parcelize'.
Destination не менялся; Money — ваш собственный класс, а LocalDate приходит из JDK, и править его вы не можете.
@Parcelize
data class Order(
val id: Long,
val title: String,
val total: Money, // ваш класс, аннотации на нём нет
val createdAt: LocalDate, // java.time — не ваш, менять нельзя
) : Parcelable
// в nav_graph.xml объявлено: <argument android:name="order" app:argType="...Order" />
Найдите и исправьте причину, не меняя того, что показывает экран.
@Parcelize пишет в Parcel только известные ему типы, а Money и LocalDate ему неизвестны. Money — ваш класс, пометьте и его @Parcelize. Для LocalDate задайте TypeParceler, который его закодирует, либо выбросьте поле и передавайте id.
- ✗Винить Safe Args или граф навигации, а не неподдержанные типы свойств
- ✗Считать, что
@Parcelizeоткатится кSerializableили рефлексии для незнакомого типа - ✗Забывать, что для чужого типа решение всё-таки есть —
TypeParceler
- →Когда передать id и подгрузить объект заново — всё равно лучший ответ?
- →Что ограничивает размер объекта, который стоит класть в аргумент навигации?
Что произошло
@Parcelize — это генератор кода, а не рефлексия. Он умеет писать в Parcel фиксированный набор типов: примитивы, String, Parcelable, коллекции из них и ещё несколько известных. Встретив свойство типа, для которого он не знает способа записи, он останавливает сборку — это ошибка компиляции, а не падение в рантайме.
Здесь неизвестны сразу два типа: Money и LocalDate. Решения у них разные, потому что один класс ваш, а другой нет.
// 1. Money — ваш класс: помечаем его тоже
@Parcelize
data class Money(val amount: Long, val currency: String) : Parcelable
// 2. LocalDate — чужой: описываем, как его писать и читать
object LocalDateParceler : Parceler<LocalDate> {
override fun create(parcel: Parcel): LocalDate = LocalDate.ofEpochDay(parcel.readLong())
override fun LocalDate.write(parcel: Parcel, flags: Int) = parcel.writeLong(toEpochDay())
}
@Parcelize
@TypeParceler<LocalDate, LocalDateParceler>
data class Order(
val id: Long,
val title: String,
val total: Money,
val createdAt: LocalDate,
) : Parcelable
Третий путь — не носить модель через навигацию вовсе: передать id: Long и дать экрану загрузить Order самому. Это часто и есть правильный ответ: аргумент навигации переживает смерть процесса в Bundle, и держать там весь объект дорого и хрупко.