读写Parcelable对象的数组

Use*_*337 74 android 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];
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

更新:

将Object数组转换为a ArrayList并将其添加到parcel是否可以?例如,写作时:

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

阅读时:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

但现在我得到了NullPointerException.以上方法是否正确?为什么要投NPE?

Mic*_*ael 151

您需要使用该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);
}
Run Code Online (Sandbox Code Playgroud)

你不应该使用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);
}
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,在`如果(!parcelableArray =空)中的语句{...}`可以简化为`resultArray = Arrays.copyOf(parcelableArray,parcelableArray.length,MyClass的[]类);` (3认同)

yor*_*rkw 36

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

根据API,readParcelableArray方法返回Parcelable数组(Parcelable []),它不能简单地转换为MyClass数组(MyClass []).

但是现在我得到Null Pointer Exception.

没有详细的异常堆栈跟踪很难说明确切的原因.


假设您已经使MyClass正确实现了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];
    }
  };

}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

您还可以使用以下方法:

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

  private ClassABC(Parcel in) {
      mObjList = new ArrayList<ClassABC>();
      in.readTypedList(mObjList, ClassABC.CREATOR);
  }
Run Code Online (Sandbox Code Playgroud)

  • 不应该是`MyClass.class.getClassLoader()`而不是`getClass().getClassLoader()`?因为我认为类加载器用于查找我们正在尝试阅读的Parceleable类. (5认同)

Gio*_*esi 10

我有类似的问题,并以这种方式解决了.我在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;
}
Run Code Online (Sandbox Code Playgroud)

每当我需要读取一个可分割的MyClass对象数组时,例如来自一个意图:

MyClass[] objects = MyClass.toMyObjects(getIntent().getParcelableArrayExtra("objects"));
Run Code Online (Sandbox Code Playgroud)

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

public static MyClass[] toMyObjects(Parcelable[] parcelables) {
    if (parcelables == null)
        return null;
    return Arrays.copyOf(parcelables, parcelables.length, MyClass[].class);
}
Run Code Online (Sandbox Code Playgroud)


Epi*_*rce 5

您需要使用该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);
}
Run Code Online (Sandbox Code Playgroud)

对于列表,您可以执行以下操作:

  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);
  }
Run Code Online (Sandbox Code Playgroud)