Proguard在Parcelable类中导致RuntimeException(解组未知类型代码)

时间:2014-01-24 21:22:18

标签: android

如果我离开我的应用程序并在一段时间后打开它,我会收到此异常。我的主要活动包括一个包含三个不同片段的ViewPager。我也在Application类中做了一些我不认为与问题有关的东西。

这是一个例外:

  

RuntimeException(@Parcel:readValue:2065){无法启动活动   ComponentInfo {com.emu / com.emu.ActivityMain}:   java.lang.RuntimeException:Parcel android.os.Parcel@419526d0:   在偏移332处解组未知类型代码2131361816

我发现谷歌分析中的用户手机上发生了很多这种异常。所有这些都是相同的,除了@v之后的数字和@之后的十六进制数,在上面的异常中是2065和419526d0。

该异常不指向任何代码行。我搜索了这个,似乎与错误写入包裹有关。虽然我的MainActivity中没有任何包裹。我不知道是什么原因引起的。

---编辑------------------------------------------- -----------------------------

我转载了这个例外。它发生在应用程序离开主页按钮,并在打开其他内存消耗应用程序后从内存中清除。再次启动它时会发生异常。直到现在我才认为从最近的任务或从DDMS关闭应用程序具有相同的效果,但显然它没有。

@EricWoodruf帮我发现包裹在导入的库中。我在PagerSlidingTabStrip中找到了我从网上下载的包裹。这是与包裹相关的代码,但我真的不知道这里有什么问题:

public class PagerSlidingTabStrip extends HorizontalScrollView
{
    @Override
    public void onRestoreInstanceState(Parcelable state)
    {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        currentPosition = savedState.currentPosition;
        requestLayout();
    }

    @Override
    public Parcelable onSaveInstanceState()
    {
        Parcelable superState = super.onSaveInstanceState();
        SavedState savedState = new SavedState(superState);
        savedState.currentPosition = currentPosition;
        return savedState;
    }

    static class SavedState extends BaseSavedState
    {
        int currentPosition;

        public SavedState(Parcelable superState)
        {
            super(superState);
        }

        private SavedState(Parcel in)
        {
            super(in);
            currentPosition = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags)
        {
            super.writeToParcel(parcel, flags);
            parcel.writeInt(currentPosition);
        }

        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>()
        {
            @Override
            public SavedState createFromParcel(Parcel in)
            {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size)
            {
                return new SavedState[size];
            }
        };
    }
}

----编辑2 ----------------------------------------- ------------------------

在我能够重现这个问题之后,我发现这只发生在由我的钥匙签名的Artifact中!调试一个没有问题!

我在工件上禁用了proguard,它就像一个没有例外的魅力。但是,导致这个问题的原因是什么?

我尝试将此添加到proguard但不起作用:

-keep class toolfa.android.base.ui.PagerSlidingTabStrip { *; }
-dontwarn toolfa.android.base.ui.PagerSlidingTabStrip

这是我当前的proguard配置:

-keep class com.nineoldandroids.** { *; }
-dontwarn com.nineoldandroids.**

-keep class ir.adad.** { *; }
-dontwarn ir.adad.**

-keep class android.support.v4.** { *; }
-dontwarn android.support.v4.**

-keep class toolfa.android.base.ui.PagerSlidingTabStrip { *; }
-dontwarn toolfa.android.base.ui.PagerSlidingTabStrip

-keep class toolfa.android.sega.ActivityEmulator { *; }
-keep class toolfa.android.sega.Zip { *; }

1 个答案:

答案 0 :(得分:51)

正如我们在评论中发现的那样,异常是ProGuard混淆Parcelable类的结果。解决方法是将此代码段包含在ProGuard配置文件中:

-keepclassmembers class * implements android.os.Parcelable {
    static ** CREATOR;
}

我想这里的具体问题是ProGuard模糊了CREATOR的{​​{1}}成员,但由于PagerSlidingTabStripView.BaseSavedState的子类,超类成员仍然可用(这就是为什么它没有抛出BadParcelableException),但它使用不同的数据结构,并且没有将自定义属性写入SavedState输出。

ProGuard Manual中提供了针对Android应用程序的推荐配置,并详细说明了条目。例如,它包括您应该保留清单或其他XML文件中使用的所有类名。