2012-04-09 104 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); 
    }