parceling枚举时的ArrayIndexOutOfBoundsException

时间:2014-10-08 08:38:17

标签: android parcelable

我看不出错误,我已经有很长一段时间没遇到这个问题了...如果重新创建了我的parcelable类会崩溃,但我找不到问题......

  • 我检查了写/读数据的顺序。
  • 我检查了我使用的功能(直接读/写vs我的custum null保存功能)

我在第一个代码块中标记了创建以下异常的行:java.lang.ArrayIndexOutOfBoundsException: length=5; index=5

简短代码

private Set<ContactType> mMatchesDataLoaded = new HashSet<ContactType>();

保存集

dest.writeInt(mMatchesDataLoaded.size());
Iterator<ContactType> it = mMatchesDataLoaded.iterator();
while (it.hasNext())
    dest.writeInt(it.next().ordinal());

阅读

int count = source.readInt();
for (int i = 0; i < count; i++)
// ---------------------------------------------------------------------------
// next line produces EXCEPTION!!! java.lang.ArrayIndexOutOfBoundsException: length=5; index=5
// ---------------------------------------------------------------------------
    mMatchesDataLoaded.add(ContactType.values()[source.readInt()]); 

完整代码

我看不出任何问题,或者更确切地说问题出在哪里......

public class ContactPhone implements Parcelable
{
    public static enum ContactType
    {
        WhatsApp,
        Viber,
        GooglePlus,
        Twitter,
        Instagram
    }

    private boolean mIsUserProfile = false;
    private boolean mHasImage;
    private int mId;
    private long mRawId;
    private String mName = null;
    private List<PhoneNumber> mNumbers = new ArrayList<PhoneNumber>();
    private DBPhoneContact mDBContact = null;

    private Set<ContactType> mMatchesDataLoaded = new HashSet<ContactType>();
    private HashMap<ContactType, List<BaseMatchContact>> mMatchesData = new HashMap<ContactType, List<BaseMatchContact>>();

    // ----------------------
    // Parcelable
    // ----------------------

    @Override
    public void writeToParcel(Parcel dest, int flags)
    {
        ParcelBundleUtils.writeBoolean(dest, mIsUserProfile);
        ParcelBundleUtils.writeBoolean(dest, mHasImage);
        ParcelBundleUtils.writeIntegerNullSafe(dest, mId);
        ParcelBundleUtils.writeLongNullSafe(dest, mRawId);
        ParcelBundleUtils.writeStringNullSafe(dest, mName);
        dest.writeList(mNumbers);

        ParcelBundleUtils.writeLongNullSafe(dest, mDBContact != null ? mDBContact.getId() : null);

        // save set
        dest.writeInt(mMatchesDataLoaded.size());
        Iterator<ContactType> it = mMatchesDataLoaded.iterator();
        while (it.hasNext())
            dest.writeInt(it.next().ordinal());

        // save HashMap
        dest.writeInt(mMatchesData.size());
        for (Map.Entry<ContactType, List<BaseMatchContact>> entry : mMatchesData.entrySet())
        {
            dest.writeInt(entry.getKey().ordinal());
            dest.writeInt(entry.getValue().size());
            for (int i = 0; i < entry.getValue().size(); i++)
                dest.writeParcelable(entry.getValue().get(i), 0);
        }
    }

    public void readFromParcel(Parcel source)
    {
        mIsUserProfile = ParcelBundleUtils.readBoolean(source);
        mHasImage = ParcelBundleUtils.readBoolean(source);
        mId = ParcelBundleUtils.readIntegerNullSafe(source);
        mRawId = ParcelBundleUtils.readLongNullSafe(source);
        mName = ParcelBundleUtils.readStringNullSafe(source);
        source.readList(mNumbers, PhoneNumber.class.getClassLoader());

        Long id = ParcelBundleUtils.readLongNullSafe(source);
        mDBContact = null;
        if (id != null)
            mDBContact = MainApp.getDS().getDBPhoneContactDao().load(id);

        // read set
        int count = source.readInt();
        for (int i = 0; i < count; i++)
// ---------------------------------------------------------------------------
// next line produces EXCEPTION!!! java.lang.ArrayIndexOutOfBoundsException: length=5; index=5
// ---------------------------------------------------------------------------
            mMatchesDataLoaded.add(ContactType.values()[source.readInt()]); 

        // read HashMap
        count = source.readInt();
        for (int i = 0; i < count; i++)
        {
            ContactType type = ContactType.values()[source.readInt()];
            Class<?> clazz = BaseDef.getMatchClass(type);
            // L.d(this, "Classloader: " + clazz.getName() + " type: " + type.name());
            int size = source.readInt();
            List<BaseMatchContact> list = new ArrayList<BaseMatchContact>();
            for (int j = 0; j < size; j++)
                list.add((BaseMatchContact) source.readParcelable(clazz.getClassLoader()));
            mMatchesData.put(type, list);
        }
    }
}

PhoneNumber类实现了parcelable,非常简单,读/写如下:

@Override
public void writeToParcel(Parcel dest, int flags)
{
    ParcelBundleUtils.writeStringNullSafe(dest, mName);
    ParcelBundleUtils.writeStringNullSafe(dest, mNormNumber);
    ParcelBundleUtils.writeStringNullSafe(dest, mNumber);
}

public void readFromParcel(Parcel source)
{
    mName = ParcelBundleUtils.readStringNullSafe(source);
    mNormNumber = ParcelBundleUtils.readStringNullSafe(source);
    mNumber = ParcelBundleUtils.readStringNullSafe(source);
}

这是我的助手功能:

public static void writeBoolean(Parcel p, boolean b)
{
    p.writeByte((byte) (b ? 1 : 0));
}

public static boolean readBoolean(Parcel p)
{
    return p.readByte() == 1;
}

public static void writeStringNullSafe(Parcel p, String s)
{
    p.writeByte((byte) (s != null ? 1 : 0));
    if (s != null)
        p.writeString(s);
}

public static void writeIntegerNullSafe(Parcel p, Integer i)
{
    p.writeByte((byte) (i != null ? 1 : 0));
    if (i != null)
        p.writeInt(i);
}

public static void writeLongNullSafe(Parcel p, Long l)
{
    p.writeByte((byte) (l != null ? 1 : 0));
    if (l != null)
        p.writeLong(l);
}

public static void writeDoubleNullSafe(Parcel p, Double d)
{
    p.writeByte((byte) (d != null ? 1 : 0));
    if (d != null)
        p.writeDouble(d);
}

public static void writeParcelableNullSafe(Parcel p, Parcelable d, int flags)
{
    p.writeByte((byte) (d != null ? 1 : 0));
    if (d != null)
        p.writeParcelable(d, flags);
}

public static String readStringNullSafe(Parcel p)
{
    boolean isPresent = p.readByte() == 1;
    return isPresent ? p.readString() : null;
}

public static Integer readIntegerNullSafe(Parcel p)
{
    boolean isPresent = p.readByte() == 1;
    return isPresent ? p.readInt() : null;
}

public static Long readLongNullSafe(Parcel p)
{
    boolean isPresent = p.readByte() == 1;
    return isPresent ? p.readLong() : null;
}

public static Double readDoubleNullSafe(Parcel p)
{
    boolean isPresent = p.readByte() == 1;
    return isPresent ? p.readDouble() : null;
}

@SuppressWarnings("unchecked")
public static <T extends Parcelable> T readParcelableNullSafe(Parcel p, ClassLoader classLoader)
{
    boolean isPresent = p.readByte() == 1;
    return isPresent ? (T) p.readParcelable(classLoader) : null;
}

2 个答案:

答案 0 :(得分:1)

int count = source.readInt(); // index is raised + 1
for (int i = 0; i < count; i++)
    mMatchesDataLoaded.add(ContactType.values()[source.readInt()]);  // index is raised by 1, starting with 1!

你从0循环到4,但是source.readInt()已被调用一次,所以你总共调用了5次。

答案 1 :(得分:0)

ContactType包含5个值,从索引0到索引4.您正在尝试访问索引5,该索引不存在。

 mMatchesDataLoaded.add(ContactType.values()[source.readInt()]); 

source.readInt()给你一个5,试着弄清楚,为什么它包含这个值。

我的猜测是writeToParcel写了这个5,尝试检查mMatchesDataLoaded,它可能包含一些额外的不需要的数据。