Program Tip

Parcelable 객체 배열 읽기 및 쓰기

programtip 2020. 10. 20. 08:03
반응형

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?

최신 정보:

객체 배열을로 변환하고 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를 던지는 이유는 무엇입니까?


다음 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);
}

오류 / AndroidRuntime (5880) : 원인 : java.lang.ClassCastException : [Landroid.os.Parcelable;

API 에 따르면 readParcelableArray 메서드는 Parcelable 배열 (Parcelable [])을 반환하는데, 이는 단순히 MyClass 배열 (MyClass [])로 캐스팅 할 수 없습니다.

하지만 이제 Null Pointer Exception이 발생합니다.

자세한 예외 스택 추적없이 정확한 원인을 알 수 없습니다.


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);
  }

비슷한 문제가 있었는데 이렇게 해결했습니다. Parcelable 배열을 MyClass 개체 배열로 변환하기 위해 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);
}

다음 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);
}

목록의 경우 다음을 수행 할 수 있습니다.

  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);
  }

참고 URL : https://stackoverflow.com/questions/10071502/read-writing-arrays-of-parcelable-objects

반응형