包裹反序列化未知类型代码

21
我们在播放商店记录的崩溃报告中遇到了这个错误。我们在所有的测试中都无法复制这个错误。是否有其他人也遇到了同样的问题或者有解决方案?问题是,我们甚至不知道该如何复制这个错误。
所有Parcelable对象都已定义CREATOR、writeToParcel()和constructor。所有列表和复杂类型都已初始化并进行了空值检查。
java.lang.RuntimeException: Unable to start activity ComponentInfo{au.com.company/au.com.company.DetailsActivity}: java.lang.RuntimeException: Parcel android.os.Parcel@42d6e270: Unmarshalling unknown type code 6881381 at offset 11268
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2247)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2297)
at android.app.ActivityThread.access$700(ActivityThread.java:152)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1282)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5328)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Parcel android.os.Parcel@42d6e270: Unmarshalling unknown type code 6881381 at offset 11268
at android.os.Parcel.readValue(Parcel.java:2032)
at android.os.Parcel.readMapInternal(Parcel.java:2225)
at android.os.Bundle.unparcel(Bundle.java:223)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1240)
at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:861)
at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1104)
at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1086)
at android.support.v4.app.FragmentManagerImpl.dispatchCreate(SourceFile:1872)
at android.support.v4.app.FragmentActivity.onCreate(SourceFile:215)
at android.support.v7.app.ActionBarActivity.onCreate(SourceFile:97)
at au.com.company.DetailsActivity.onCreate(SourceFile:40)
at android.app.Activity.performCreate(Activity.java:5250)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1097)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
... 11 more

启用Proguard后出现非常相似的异常,我自己还没有解决。 - Rolf ツ
在某些地方发现我们要么对字段排序错误,要么在create/constructor和writeToParcel之间缺少一些字段。还将CREATOR添加到所有嵌套类中,然后问题就解决了。最好是将屏幕分成相同的文件,并在每个方法中为每个嵌套类匹配每个字段。这是非常繁琐的工作,但不再看到那个错误了。 - ManiacalG
也许这可以帮助某些人。启用开发者模式并始终杀死活动可以100%地复现此问题。 - Aerim
7个回答

23
我遇到了一个问题,涉及自定义视图(View)并且它有自己的View.BaseSavedState实现。后来发现该视图的writeToParcel()方法中调用方法的顺序有误。
很烦恼,需要一步步调试Android SDK,直到调用unparcel()方法的Bundle类才找到问题。
synchronized void unparcel() {
    if (mParcelledData == null) {
        return;
    }

    int N = mParcelledData.readInt();
    if (N < 0) {
        return;
    }
    if (mMap == null) {
        mMap = new HashMap<String, Object>(N);
    }
    mParcelledData.readMapInternal(mMap, N, mClassLoader);
    mParcelledData.recycle();
    mParcelledData = null;
}

您日志中的第223行正是readMapInternal()方法的调用。在此方法中,Parcel对象会迭代其项,逐个读取值。通常情况下,问题发生在某些东西按错误顺序写入时。方法Parcel.readValue(ClassLoader loader)将按照它们被写入的顺序读取它们,但是如果您有自定义视图或对象,如果它们按不同于您现在正在读取它们的顺序编写,则在下一个要读取的项中可能会发生错误。

因此,我通过识别最后成功读取的项目来找到了问题。您通常可以通过检查其创建者类名(如果它是自定义视图或对象)来识别它。请检查Parcel类的方法readParcelableCreator():

public final <T extends Parcelable> Parcelable.Creator<T> readParcelableCreator(
        ClassLoader loader) {
    String name = readString();
    if (name == null) {
        return null;
    }
...
}

你可以检查创建者的类名字符串。如果是自定义的,你可以立即识别它。然后,如果下一次读取导致应用程序崩溃,你几乎可以确定罪魁祸首是前一次读取。
希望这有所帮助。

我理解了你的解释,但还不太明白如何调试这个东西 :) 有什么帮助吗?我已经仔细检查了所有我的SavedStates和订单,都没问题。 - natario
提供的解决方案对我来说并不完全有效,但它引导我调查了我在其中一个自定义视图上拥有的View.BaseSavedState实现。 - Hadi Tok

8
我也遇到了这个错误,但我找到了问题所在。我将一个变量从long更改为int,但忘记更改以下内容:
我之前使用了parcel.writeLong(number),然后读取时使用了number=parcel.readInt()。正确的做法是使用parcel.writeInt(number)

我犯的确切错误! - Sufian
我的错误在于将parcel.writeValue(object)与parcel.readParcelable(Class.class.getClassLoader())结合使用。必须使用parcel.writeParcelable()和parcel.readParcelable()。 - Pedro Romão

3

请检查您的Parcelable类及其子类中readwrite的顺序。

writeToParcel的顺序应该与MyParcelable(Parcel in)方法中读取的顺序相同。


1
这对我来说是正确的答案!谢谢@Blake - Lubomir Babev

0
如果您有自己的SavedState类,请确保它没有被混淆,也不要混淆它的CREATOR静态属性。
可以使用以下代码:
# Keeping *SavedState and *SavedState#CREATOR
-keep public final class * extends android.view.AbsSavedState
-keepclassmembers public final class * extends android.view.AbsSavedState { *; }

0

当我在阅读包裹源代码时,我遇到了这个错误,尝试将其保存在Map中而不是检查返回值是否为null:

String tag = in.readString();
Double value = in.readDouble();
while (tag != null && value != null) {
    this.observations.put(tag, value);
    tag = in.readString();
    value = in.readDouble();
};

应该存储一个整数以正确迭代包裹:

int numObservations = in.readInt();
String key;
Double value;
for (int i = 0; i < numObservations; i++) {
    key = in.readString();
    value = in.readDouble();
    map.put(tag, value);
}

0

在读取包裹时,我遇到了相同的错误。

检查您的Parcelable类及其子类的读写顺序和数量


-2
在我的情况下,我试图将一个 arrayList 分配给一个 List,这会触发该错误。

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