Parcelable을 비 정렬 화하는 문제
Parcelable 을 구현하는 몇 가지 클래스가 있으며 이러한 클래스 중 일부는 서로를 속성으로 포함합니다. 활동간에 전달하기 위해 클래스를 Parcel 로 마샬링하고 있습니다 . 소포로 마샬링하면 잘 작동하지만 마샬링을 해제하려고하면 다음 오류가 발생합니다.
...
AndroidRuntime E Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: schemas.Arrivals.LocationType
AndroidRuntime E at android.os.Parcel.readParcelable(Parcel.java:1822)
AndroidRuntime E at schemas.Arrivals.LayoverType.<init>(LayoverType.java:121)
AndroidRuntime E at schemas.Arrivals.LayoverType.<init>(LayoverType.java:120)
AndroidRuntime E at schemas.Arrivals.LayoverType$1.createFromParcel(LayoverType.java:112)
AndroidRuntime E at schemas.Arrivals.LayoverType$1.createFromParcel(LayoverType.java:1)
AndroidRuntime E at android.os.Parcel.readTypedList(Parcel.java:1509)
AndroidRuntime E at schemas.Arrivals.BlockPositionType.<init>(BlockPositionType.java:244)
AndroidRuntime E at schemas.Arrivals.BlockPositionType.<init>(BlockPositionType.java:242)
AndroidRuntime E at schemas.Arrivals.BlockPositionType$1.createFromParcel(BlockPositionType.java:234)
AndroidRuntime E at schemas.Arrivals.BlockPositionType$1.createFromParcel(BlockPositionType.java:1)
...
LayoverType
클래스 (어디에 실패 것) :
public class LayoverType implements Parcelable {
protected LocationType location;
protected long start;
protected long end;
public LayoverType() {}
public LocationType getLocation() {
return location;
}
public void setLocation(LocationType value) {
this.location = value;
}
public long getStart() {
return start;
}
public void setStart(long value) {
this.start = value;
}
public long getEnd() {
return end;
}
public void setEnd(long value) {
this.end = value;
}
// **********************************************
// for implementing Parcelable
// **********************************************
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(location, flags);
dest.writeLong(start);
dest.writeLong(end );
}
public static final Parcelable.Creator<LayoverType> CREATOR = new Parcelable.Creator<LayoverType>() {
public LayoverType createFromParcel(Parcel in) {
return new LayoverType(in);
}
public LayoverType[] newArray(int size) {
return new LayoverType[size];
}
};
private LayoverType(Parcel dest) {
location = (LocationType) dest.readParcelable(null); // it's failing here
start = dest.readLong();
end = dest.readLong();
}
}
LocationType
수업 은 다음과 같습니다 .
public class LocationType implements Parcelable {
protected int locid;
protected String desc;
protected String dir;
protected double lat;
protected double lng;
public LocationType() {}
public int getLocid() {
return locid;
}
public void setLocid(int value) {
this.locid = value;
}
public String getDesc() {
return desc;
}
public void setDesc(String value) {
this.desc = value;
}
public String getDir() {
return dir;
}
public void setDir(String value) {
this.dir = value;
}
public double getLat() {
return lat;
}
public void setLat(double value) {
this.lat = value;
}
public double getLng() {
return lng;
}
public void setLng(double value) {
this.lng = value;
}
// **********************************************
// for implementing Parcelable
// **********************************************
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt (locid);
dest.writeString(desc );
dest.writeString(dir );
dest.writeDouble(lat );
dest.writeDouble(lng );
}
public static final Parcelable.Creator<LocationType> CREATOR = new Parcelable.Creator<LocationType>() {
public LocationType createFromParcel(Parcel in) {
return new LocationType(in);
}
public LocationType[] newArray(int size) {
return new LocationType[size];
}
};
private LocationType(Parcel dest) {
locid = dest.readInt ();
desc = dest.readString();
dir = dest.readString();
lat = dest.readDouble();
lng = dest.readDouble();
}
}
업데이트 2 : Parcel의 소스 에서 가져온 다음 코드에서 실패하고 있음을 알 수 있습니다 .
Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader);
클래스를 찾을 수없는 이유는 무엇입니까? 그것은 존재하고 구현 Parcelable
합니다.
이것이 "답변"에서 대답되지 않았기 때문에 나는 대답을 게시 할 것입니다. @ Max-Gontar가 지적했듯이 올바른 ClassLoader를 얻고 ClassNotFound 예외를 제거하려면 LocationType.class.getClassLoader ()를 사용해야합니다. 즉 :
in.readParceleable(LocationType.class.getClassLoader());
다음 설정에서 동일한 문제가 발생했습니다. 일부 핸들러는 메시지를 생성하고 메신저를 통해 원격 서비스로 보냅니다.
메시지에는 Parcelable 하위 항목을 넣은 번들이 포함되어 있습니다.
final Message msg = Message.obtain(null, 0);
msg.getData().putParcelable("DOWNLOADFILEURLITEM", downloadFileURLItem);
messenger.send(msg);
원격 서비스가 배송을 취소하려고 할 때 동일한 예외가 발생했습니다. 제 경우에는 원격 서비스가 실제로 별도의 OS 프로세스임을 감독했습니다. 따라서 서비스 측에서 unparcelling 프로세스에서 사용할 현재 클래스 로더를 설정해야했습니다.
final Bundle bundle = msg.getData();
bundle.setClassLoader(getClassLoader());
DownloadFileURLItem urlItem = (DownloadFileURLItem)
bundle.getParcelable("DOWNLOADFILEURLITEM");
Bundle.setClassLoader는 적절한 Parcelable 클래스를로드하는 데 사용되는 클래스 로더를 설정합니다. 원격 서비스에서는 현재 클래스 로더로 재설정해야합니다.
문제는 내 응용 프로그램 ClassLoader를 unmarshalling 함수에 전달하지 않는다는 것입니다.
in.readParceleable(getContext().getClassLoader());
대신 :
in.readParceleable(null);
또는
in.readParceleable(MyClass.class.getClassLoader());
여기에 2 센트 만 더 해주면 반나절 넘게 머리를 긁적 거리며 잃었 기 때문입니다. writes 메서드와 reads 메서드를 똑같은 순서로 배치하지 않으면이 오류가 발생할 수 있습니다. 예를 들어 다음은 잘못된 것입니다.
@Override
// Order: locid -> desc -> lat -> dir -> lng
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt (locid);
dest.writeString(desc);
dest.writeDouble(lat);
dest.writeString(dir);
dest.writeDouble(lng);
}
// Order: locid -> desc -> dir -> lat -> lng
private LocationType(Parcel dest) {
locid = dest.readInt();
desc = dest.readString();
dir = dest.readString();
lat = dest.readDouble();
lng = dest.readDouble();
}
그건 그렇고 저자는 이것을 올바르게했지만 언젠가는 누군가를 도울 수 있습니다.
Parcelable에 익숙하지 않지만 Serialization과 같은 경우 인터페이스를 구현하는 개체를 작성하기위한 각 호출은 writeToParcel ()에 대한 재귀 호출을 발생시킵니다. 따라서 호출 스택에있는 무언가가 실패하거나 null 값을 쓰는 경우 호출을 시작한 클래스가 올바르게 구성되지 않을 수 있습니다.
다음을 시도하십시오. writeToParcel ()에 대한 첫 번째 호출에서 시작하는 모든 클래스를 통해 writeToParcel () 호출 스택을 추적하고 모든 값이 올바르게 전송되는지 확인하십시오.
나는 ClassNotFoundException도 얻었고 내 솔루션을 게시하면 여기에 대답이 나를 올바른 방향으로 이끌었습니다. 내 시나리오는 내포 된 구획 가능 객체가 있다는 것입니다. 객체 A는 객체 B의 ArrayList를 포함합니다. 둘 다 Parcelable을 구현합니다. 클래스 A에 B 개체 목록 작성 :
@Override
public void writeToParcel(Parcel dest, int flags) {
...
dest.writeList(getMyArrayList());
}
클래스 A의 목록 읽기 :
public ObjectA(Parcel source) {
...
myArrayList= new ArrayList<B>();
source.readList(myArrayList, B.class.getClassLoader());
}
감사합니다!
writeParcelable 및 readParcelable을 사용하는 대신 writeToParcel 및 createFromParcel을 직접 사용하십시오. 따라서 더 나은 코드는 다음과 같습니다.
@Override
public void writeToParcel(Parcel dest, int flags) {
location.writeToParcel(dest, flags);
dest.writeLong(start);
dest.writeLong(end );
}
public static final Parcelable.Creator<LayoverType> CREATOR = new Parcelable.Creator<LayoverType>() {
public LayoverType createFromParcel(Parcel in) {
return new LayoverType(in);
}
public LayoverType[] newArray(int size) {
return new LayoverType[size];
}
};
private LayoverType(Parcel dest) {
location = LocationType.CREATOR.createFromParcel(dest);
start = dest.readLong();
end = dest.readLong();
}
글쎄, 나는 똑같은 문제를 가지고 있었고 그것이 해결책이라고 부르는지 전혀 알지 못하는 매우 어리석은 방식으로 해결했습니다.
다른 활동에 전달하려는이 수업이 있다고 가정 해 보겠습니다.
public class Person implements Parcelable,Serializable{
public String Name;
public int Age;
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
public SeriesInfo(Parcel in) {
age= in.readInt(); //her was my problem as I have put age befor name
//while in the writeToParcel function I have defined
//dest.writeInt(age) after in.readString();???!!!!
name= in.readString();
}
}
그게 내가 다음을 변경했을 때입니다.
dest.writeString(name);
dest.writeInt(age);
...에
dest.writeInt(age);
dest.writeString(name);
문제가 해결 되었나요 ??? !!!!
List 객체 유형의 속성을 가진 Object가있는 경우 속성을 읽을 때 클래스 로더를 전달해야합니다. 예를 들면 다음과 같습니다.
public class Mall implements Parcelable {
public List<Outstanding> getOutstanding() {
return outstanding;
}
public void setOutstanding(List<Outstanding> outstanding) {
this.outstanding = outstanding;
}
protected Mall(Parcel in) {
outstanding = new ArrayList<Outstanding>();
//this is the key, pass the class loader
in.readList(outstanding, Outstanding.class.getClassLoader());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(outstanding);
}
public static final Parcelable.Creator<Mall> CREATOR = new Parcelable.Creator<Mall>() {
public Mall createFromParcel(Parcel in) {
return new Mall(in);
}
public Mall[] newArray(int size) {
return new Mall[size];
}
};
}
참고 : Outstanding 클래스가 Parceable 인터페이스를 구현하는 것이 중요합니다.
참고 URL : https://stackoverflow.com/questions/1996294/problem-unmarshalling-parcelables
'development' 카테고리의 다른 글
공백이있는 경로를 매개 변수로 bat 파일에 전달 (0) | 2020.12.10 |
---|---|
파일에서 줄을 찾아 제거 (0) | 2020.12.10 |
쿠키의 만료 시간을 얻는 방법 (0) | 2020.12.10 |
CakePHP 용으로 생성 된 기존 MySQL 데이터베이스에서 ER 다이어그램 생성 (0) | 2020.12.10 |
jQuery의 다중 선택기 체인? (0) | 2020.12.10 |