minifyEnabled 设置为 true 后出现 NotSerializableException: kotlin.UNINITIALIZED_VALUE

3
在应用的build.gradle脚本中设置minifyEnabled true后,我开始收到以下异常:
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.**.* { *; } 白名单所有应用程序类,但没有成功。

3个回答

5

我遇到了同样的问题,当前答案是错误的:在lazy上添加@delegate:Transient会使反序列化时的后备字段变为null。

由于这个问题只出现在minifyEnabled = true时,这是一个Proguard/R8问题。我通过在我的proguard-rules.pro中添加以下行来解决它:

-keep class * implements kotlin.Lazy {
    *;
}

太高兴了,我找到了你的答案。我遇到了完全相同的R8问题,这解决了我的问题。 - John Gorenfeld
我仍然好奇是哪种优化方式干扰了反序列化过程。有人已经找到答案了吗? - Pedro Oliveira

0

懒惰委托在幕后使用UNINITIALIZED_VALUE对象。它用于检查变量是否已声明。在某种程度上[需要更多信息],懒惰委托在代码缩小期间改变其行为。这会创建一种情况,只要minifyEnabled被禁用,那么传递具有延迟初始化字段的对象就可以正常工作,而无需尝试对其进行序列化。但是启用缩小后,Java尝试将UNINITIALIZED_VALUE序列化,这会在运行时引发异常。

不幸的是,堆栈跟踪不能告诉您必须更新哪个类中的哪个字段。至少它告诉您哪个主类包含您损坏的Serializable类。

假设在这种情况下,some.package.SomeClass包含AnotherClass字段。要修复它,您需要找到所有实现Serializable的懒惰类字段。然后在它们上面添加@delegate:Transient,例如:

class AnotherClass: Serializable {

    …

    @delegate:Transient // <- add this
    val myLazyField by lazy { "Kotlin, why?!" }
}

这是错误的:添加@delegate:Transient会使支持字段无效,并在访问它时抛出NPE。 - Renaud Cerrato

0
我遇到了同样的问题。以下的pro-guard设置似乎能够解决这个问题:
-keepclassmembers class * implements java.io.Serializable {
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接