#android #kotlin #gradle #delegates #serializable
#Android #kotlin #gradle #делегаты #сериализуемый
Вопрос:
После настройки minifyEnabled true
в скрипте приложения build.gradle
я начал получать это исключение:
Caused by: java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = some.package.SomeClass)
at android.os.Parcel.writeSerializable(Parcel.java:1767)
…
Caused by: java.io.NotSerializableException: kotlin.UNINITIALIZED_VALUE
Произошел сбой при попытке перейти class SomeClass : Parcelable
к другому действию.
Я пытался внести в белый список все классы приложений с помощью -keep class some.package.**.* { *; }
, но безуспешно.
Ответ №1:
Я наткнулся на ту же проблему, и текущий ответ неверен: добавление @delegate:Transient
в ленивом режиме приведет к аннулированию резервного поля при десериализации.
Поскольку проблема возникает только тогда, когда minifyEnabled = true
это проблема Proguard / R8. Я решил это, добавив следующие строки в свой proguard-rules.pro
:
-keep class * implements kotlin.Lazy {
*;
}
Комментарии:
1. Я так рад, что нашел ваш ответ. Я столкнулся с точно такой же проблемой R8, и это устранило проблему.
2. Мне все еще любопытно, какой тип оптимизации мешает процессу десериализации. Кто-нибудь уже узнал?
Ответ №2:
Ленивый делегат использует UNINITIALIZED_VALUE
объект за сценой. Используется для проверки, объявлена переменная или нет. Каким-то образом [нужно больше информации] ленивый делегат изменяет свое поведение во время минимизации кода. Это создает ситуацию, когда до тех пор, пока minifyEnabled
отключен, передача объекта с отложенным инициализированным полем работает нормально без попыток его сериализации. Но после включения минимизации Java пытается сериализоваться UNINITIALIZED_VALUE
, что вызывает исключение во время выполнения.
К сожалению, stacktrace не сообщает вам точно, какое поле в каком классе вы должны обновить. По крайней мере, это подскажет вам, какой из основных классов содержит ваш сломанный Serializable
класс.
Давайте предположим, что в данном случае some.package.SomeClass
содержит AnotherClass
поле. Чтобы исправить это, вам нужно найти все поля ленивого класса, где classes реализует Serializable
. Затем добавьте @delegate:Transient
к ним, например.
class AnotherClass: Serializable {
…
@delegate:Transient // <- add this
val myLazyField by lazy { "Kotlin, why?!" }
}
Комментарии:
1. Это неправильно: добавление
@delegate:Transient
приведет к аннулированию резервного поля и вызовет NPE при доступе к нему.