2012-04-09 108 views
64

我具有以下类读取和写入对象的数组从/到一个包裹:读取&Parcelable的书写阵列对象

class ClassABC extends Parcelable { 
    MyClass[] mObjList; 

    private void readFromParcel(Parcel in) { 
     mObjList = (MyClass[]) in.readParcelableArray(
       com.myApp.MyClass.class.getClassLoader())); 
    } 

    public void writeToParcel(Parcel out, int arg1) { 
     out.writeParcelableArray(mObjList, 0); 
    } 

    private ClassABC(Parcel in) { 
     readFromParcel(in); 
    } 

    public int describeContents() { 
     return 0; 
    } 

    public static final Parcelable.Creator<ClassABC> CREATOR = 
      new Parcelable.Creator<ClassABC>() { 

     public ClassABC createFromParcel(Parcel in) { 
      return new ClassABC(in); 
     } 

     public ClassABC[] newArray(int size) { 
      return new ClassABC[size]; 
     } 
    }; 
} 

在上面的代码中,我得到一个ClassCastException读取readParcelableArray时:

错误/ AndroidRuntime(5880):引起:java.lang.ClassCastException:[Landroid.os.Parcelable;

上述代码有什么问题?在写对象数组时,我应该先将数组转换为ArrayList

UPDATE:

是否确定对象数组转换为ArrayList并添加它来包裹?例如,书写时:

ArrayList<MyClass> tmpArrya = new ArrayList<MyClass>(mObjList.length); 
    for (int loopIndex=0;loopIndex != mObjList.length;loopIndex++) { 
     tmpArrya.add(mObjList[loopIndex]); 
    } 
    out.writeArray(tmpArrya.toArray()); 

读取时:

final ArrayList<MyClass> tmpList = 
      in.readArrayList(com.myApp.MyClass.class.getClassLoader()); 
    mObjList= new MyClass[tmpList.size()]; 
    for (int loopIndex=0;loopIndex != tmpList.size();loopIndex++) { 
     mObjList[loopIndex] = tmpList.get(loopIndex); 
    } 

但现在我得到了NullPointerException。以上方法是否正确?为什么它会抛出NPE?

+0

mConversationMemberList的类型是什么? – Chetan 2012-04-09 10:08:42

+0

我已经更新了这个问题,它是MyClass []类型的。 – User7723337 2012-04-09 10:14:45

回答

139

您需要使用Parcel.writeTypedArray()方法写入阵列并读取它与Parcel.createTypedArray()方法,像这样:

MyClass[] mObjList; 

public void writeToParcel(Parcel out) { 
    out.writeTypedArray(mObjList, 0); 
} 

private void readFromParcel(Parcel in) { 
    mObjList = in.createTypedArray(MyClass.CREATOR); 
} 

原因为什么你不应该使用readParcelableArray()/writeParcelableArray()方法是readParcelableArray()真的创建Parcelable[]作为结果。这意味着您不能将方法的结果投射到MyClass[]。相反,您必须创建一个与结果长度相同的MyClass数组,并将结果数组中的每个元素复制到MyClass数组中。

Parcelable[] parcelableArray = 
     parcel.readParcelableArray(MyClass.class.getClassLoader()); 
MyClass[] resultArray = null; 
if (parcelableArray != null) { 
    resultArray = Arrays.copyOf(parcelableArray, parcelableArray.length, MyClass[].class); 
} 
+1

谢谢,这就是诀窍!这应该在文档中澄清,因为方法命名使得它听起来像一个Parcelable数组是什么应该写的,当它明确更多的代码。 – Tom 2013-01-18 05:45:38

+0

是的,该方法的名称有点混乱。当我遇到这个问题时,解决它的唯一方法就是阅读Android源代码,这就是我决定写这个答案的原因。 – Michael 2013-01-18 07:31:21

+3

顺便说一句,'if(parcelableArray!= null){...}'中的语句可以简化为'resultArray = Arrays.copyOf(parcelableArray,parcelableArray.length,MyClass []。class);' – CrimsonX 2013-07-24 19:37:26

34

错误/ AndroidRuntime(5880):引起:java.lang.ClassCastException:[Landroid.os.Parcelable;

按照API,readParcelableArray方法返回Parcelable阵列(Parcelable []),这不能简单地浇铸MyClass的阵列(MyClass的[])。

但现在我得到空指针异常。

没有详细的异常堆栈跟踪,很难确切地说出原因。


假设你已经正确MyClass的实现Parcelable,这是怎么了,我们通常的连载做/反序列化parcelable对象的数组:

public class ClassABC implements Parcelable { 

    private List<MyClass> mObjList; // MyClass should implement Parcelable properly 

    // ==================== Parcelable ==================== 
    public int describeContents() { 
    return 0; 
    } 

    public void writeToParcel(Parcel out, int flags) { 
    out.writeList(mObjList); 
    } 

    private ClassABC(Parcel in) { 
    mObjList = new ArrayList<MyClass>(); 
    in.readList(mObjList, getClass().getClassLoader()); 
    } 

    public static final Parcelable.Creator<ClassABC> CREATOR = new Parcelable.Creator<ClassABC>() { 
    public ClassABC createFromParcel(Parcel in) { 
     return new ClassABC(in); 
    } 
    public ClassABC[] newArray(int size) { 
     return new ClassABC[size]; 
    } 
    }; 

} 

希望这有助于。

您也可以使用以下方法:

public void writeToParcel(Parcel out, int flags) { 
     out.writeTypedList(mObjList); 
    } 

    private ClassABC(Parcel in) { 
     mObjList = new ArrayList<ClassABC>(); 
     in.readTypedList(mObjList, ClassABC.CREATOR); 
    } 
+5

不应该是'MyClass.class.getClassLoader()'而不是'getClass()。getClassLoader()'?因为我认为正在使用类加载器来查找我们正在尝试阅读的Parceleable类。 – 2012-10-17 03:52:25

+0

正是我不想要ClassABC,我想MyClass – Srneczek 2015-11-12 18:48:26

9

我有一个类似的问题,并以这种方式解决它。 我MyClass中限定的辅助方法,用于Parcelable的阵列转换为MyClass的对象的数组:

public static MyClass[] toMyObjects(Parcelable[] parcelables) { 
    MyClass[] objects = new MyClass[parcelables.length]; 
    System.arraycopy(parcelables, 0, objects, 0, parcelables.length); 
    return objects; 
} 

每当我需要读取MyClass的物体,例如一个parcelable阵列从意向:

MyClass[] objects = MyClass.toMyObjects(getIntent().getParcelableArrayExtra("objects")); 

编辑:这里是相同的功能的更新版本,我使用更近,以避免编译警告:

public static MyClass[] toMyObjects(Parcelable[] parcelables) { 
    if (parcelables == null) 
     return null; 
    return Arrays.copyOf(parcelables, parcelables.length, MyClass[].class); 
} 
+0

我想我现在将收藏这个答案。过去几次,我已经回来复制这个神奇的代码:D – Sufian 2015-01-09 14:06:28

+0

@Giorgio Barchiesi,在android studio中显示一条警告:源代码是Parcelable,目标是MyClass,但应用程序按预期工作。怎么样 ? – kaushik 2015-03-31 10:29:48

+0

@kaushik,感谢您的评论,我编辑了我的答案,请参阅新版本的“toMyObject”函数。 – 2017-03-03 11:32:00

2

你需要写数组使用Parcel.writeTypedArray()方法,并与Parcel.readTypedArray()方法读回,像这样:

MyClass[] mObjArray; 

public void writeToParcel(Parcel out, int flags) { 
    out.writeInt(mObjArray.length); 
    out.writeTypedArray(mObjArray, flags); 
} 

protected MyClass(Parcel in) { 
    int size = in.readInt(); 
    mObjArray = new MyClass[size]; 
    in.readTypedArray(mObjArray, MyClass.CREATOR); 
} 

对于列表,你可以做FO如下:

ArrayList<MyClass> mObjList; 

    public void writeToParcel(Parcel out, int flags) { 
     out.writeTypedList(mObjList); 
    } 

    protected MyClass(Parcel in) { 
     mObjList = new ArrayList<>(); //non-null reference is required 
     in.readTypedList(mObjList, MyClass.CREATOR); 
    }