鉴于自定义类org.example.app.MyClass implements Parcelable
,我想将List<MyClass>
写入包裹。我用
List<MyClass> myclassList = ...
parcel.writeList(myclassList);
每当我尝试用
解组课程时 List<MyClass> myclassList = new ArrayList<MyClass>();
parcel.readList(myclassList, null);
有一个"BadParcelableException: ClassNotFoundException when unmarshalling org.example.app.MyClass"
例外。
这里有什么问题?为什么找不到课程?
答案 0 :(得分:102)
不要使用null
作为ClassLoader参数时使用的框架类加载器来解组自定义类(即由应用程序提供而不是由Android框架提供的类)。使用应用程序类加载器:
parcel.readList(myclassList, getClass().getClassLoader());
每当Parcel.read*()
方法也有一个ClassLoader作为参数(例如Parcel.readList(List outVal, ClassLoader loader)
)并且你想从Parcel
读取一个应用程序类时,使用可以是的应用程序类加载器使用getClass().getClassLoader()
检索。
背景: Android附带两个类加载器:系统类加载器,它能够加载所有系统类,但是应用程序提供的系统类;和应用程序类加载器,它将系统类加载器设置为其父类,因此能够加载所有类。如果您将null设置为类加载器Parcel.readParcelableCreator()
will use the framework class loader,则会导致ClassNotFoundException。
感谢alexanderblom提供的the hint让我走上正轨。
答案 1 :(得分:18)
我相信更正确的形式是:
List<MyClass> myclassList = new ArrayList<MyClass>();
parcel.readList(myclassList, MyClass.class.getClassLoader());
因为在这里你明确地使用类加载器作为List的泛型类型。
答案 2 :(得分:4)
我遇到了同样的问题而不是parcleable我使用了捆绑
intent.setExtrasClassLoader(getClassLoader());
/* Send optional extras */
Bundle bundle = new Bundle();
bundle.putParcelable("object", mObject);
bundle.putString("stringVal", stringVal);
intent.putExtra("bundle",bundle);
在我的意图类中,我使用它来检索值:
Bundle oldBundle = intent.getBundleExtra("bundle");
ResultReceiver receiver = oldBundle.getParcelable("object");
String stringVal = oldBundle.getString("stringVal");
intent.setExtrasClassLoader(getClassLoader());
希望对某些人有帮助。
答案 3 :(得分:3)
如果您错误地将自定义视图子类化,则可能会出现此错误。
假设您是BottomNavigationView
的子类,并且希望将已保存的状态添加到onSaveInstanceState()
中的超级状态。
Parcelable样板的错误实现(从另一个类或模板复制)看起来像这样:
static class State extends BaseSavedState {
Bundle stateBundle;
//incorrect as super state uses ClassLoaderCreator
public static final Creator<State> CREATOR = new Creator<State>() {
public State createFromParcel(Parcel in) {
return new State(in);
}
public State[] newArray(int size) {
return new State[size];
}
};
State(Parcel source) {
super(source);
this.stateBundle = source.readBundle(getClass().getClassLoader());
}
State(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeBundle(stateBundle);
}
}
这不起作用,因为BottomNavigationView
的超级要求需要一个类加载器。相反,您应该仔细检查SavedState
中的BottomNavigationView
班级并使用正确的ClassLoaderCreator
而不是Creator
:
static class State extends AbsSavedState {
Bundle stateBundle;
public static final Creator<State> CREATOR = new ClassLoaderCreator<State>() {
public State createFromParcel(Parcel in, ClassLoader classLoader) {
return new State(in, classLoader);
}
@Override
public State createFromParcel(Parcel source) {
return new State(source, null);
}
public State[] newArray(int size) {
return new State[size];
}
};
State(Parcel source, ClassLoader classLoader) {
super(source, classLoader);
this.stateBundle = source.readBundle(classLoader);
}
State(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeBundle(stateBundle);
}
}
请注意,扩展android.support.v4.view.AbsSavedState
可能是比BaseSavedState
或android.view.AbsSavedState
更好的选择,因为它允许您将类加载器传递给超类:
SavedState(Parcel source, ClassLoader classLoader) {
super(source, classLoader); //available in android.support.v4.view.AbsSavedState
this.stateBundle = source.readBundle(classLoader);
}