我似乎在我的应用中遇到了一个奇怪的错误(请参阅GitHub),这是在我将对象传递给实现Parcelable
的不同活动时发生的。
我已经在Stack Overflow上查看了其他问题和答案,但我无法找到解决方案。我已经尝试了答案here,例如 - 这里仅供参考:
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
}
我还确保writeToParcel
中的方法调用是有序的。 Stack Overflow关于此问题的大多数其他问题都没有答案。
此外,我问一个新问题的原因是因为我认为我的问题是由于我在我的应用程序中使用接口的原因造成的(我稍后会对此进行扩展)。关于Stack Overflow的其他问题不适合我的特定情况。
在下文中,我通过GitHub提供了代码链接,以便您可以根据需要探索更多代码。
当我点击按钮launch a new activity(传递实现Parcelable
的对象)时,there is a crash:
Process: com.satsuware.flashcards, PID: 4664
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.satsuware.flashcards/com.satsumasoftware.flashcards.ui.FlashCardActivity}: java.lang.RuntimeException: Parcel android.os.Parcel@d2219e4: Unmarshalling unknown type code 6815860 at offset 200
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
...
Caused by: java.lang.RuntimeException: Parcel android.os.Parcel@d2219e4: Unmarshalling unknown type code 6815860 at offset 200
at android.os.Parcel.readValue(Parcel.java:2319)
at android.os.Parcel.readListInternal(Parcel.java:2633)
at android.os.Parcel.readArrayList(Parcel.java:1914)
at android.os.Parcel.readValue(Parcel.java:2264)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2592)
at android.os.BaseBundle.unparcel(BaseBundle.java:221)
at android.os.Bundle.getParcelable(Bundle.java:786)
at android.content.Intent.getParcelableExtra(Intent.java:5377)
at com.satsumasoftware.flashcards.ui.FlashCardActivity.onCreate(FlashCardActivity.java:71)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
...
我称之为上述活动(也是see GitHub):
Intent intent = new Intent(TopicDetailActivity.this, FlashCardActivity.class);
intent.putExtra(FlashCardActivity.EXTRA_TOPIC, mTopic);
intent.putExtra(FlashCardActivity.EXTRA_NUM_CARDS, mSelectedNumCards);
intent.putExtra(FlashCardActivity.EXTRA_CARD_LIST, mFilteredCards);
startActivity(intent);
要考虑的主要部分是我通过mTopic
时。这是我创建的Topic
interface。
但是,Topic
接口扩展Parcelable
,因此实现Topic
的对象还包括构造函数,CREATOR
字段以及实现{{ 1}}通常必须有。
您可以通过GitHub链接查看相关课程,但我将在下面提供这些课程的相关部分。这是Parcelable
界面:
Topic
public interface Topic extends Parcelable {
int getId();
String getIdentifier();
String getName();
Course getCourse();
ArrayList<FlashCard> getFlashCards(Context context);
class FlashCardsRetriever {
public static ArrayList<FlashCard> filterStandardCards(ArrayList<FlashCard> flashCards, @StandardFlashCard.ContentType int contentType) {
ArrayList<FlashCard> filteredCards = new ArrayList<>();
for (FlashCard flashCard : flashCards) {
boolean isPaper2 = ((StandardFlashCard) flashCard).isPaper2();
boolean condition;
switch (contentType) {
case StandardFlashCard.PAPER_1:
condition = !isPaper2;
break;
case StandardFlashCard.PAPER_2:
condition = isPaper2;
break;
case StandardFlashCard.ALL:
condition = true;
break;
default:
throw new IllegalArgumentException("content type '" + contentType + "' is invalid");
}
if (condition) filteredCards.add(flashCard);
}
return filteredCards;
}
...
}
}
:
implements Topic
在上面代码的最后一行中,您可以看到我传递public class CourseTopic implements Topic {
...
public CourseTopic(int id, String identifier, String name, Course course) {
...
}
@Override
public int getId() {
return mId;
}
@Override
public String getIdentifier() {
return mIdentifier;
}
...
protected CourseTopic(Parcel in) {
mId = in.readInt();
mIdentifier = in.readString();
mName = in.readString();
mCourse = in.readParcelable(Course.class.getClassLoader());
}
public static final Parcelable.Creator<CourseTopic> CREATOR = new Parcelable.Creator<CourseTopic>() {
@Override
public CourseTopic createFromParcel(Parcel in) {
return new CourseTopic(in);
}
@Override
public CourseTopic[] newArray(int size) {
return new CourseTopic[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mId);
dest.writeString(mIdentifier);
dest.writeString(mName);
dest.writeParcelable(mCourse, flags);
}
}
,这是我创建的mCourse
对象。这是:
Course
}
我怀疑这里可能会出现问题,这也是我的情景与其他问题不同的原因。
说实话,我不确定可能导致错误的原因,因此非常感谢答案中的解释和指导。
修改:
在 David Wasser 的建议之后,我更新了部分代码:
FlashCardActivity.java - public class Course implements Parcelable {
...
public Course(String subject, String examBoard, @FlashCard.CourseType String courseType,
String revisionGuide) {
...
}
public String getSubjectIdentifier() {
return mSubjectIdentifier;
}
public String getExamBoardIdentifier() {
return mBoardIdentifier;
}
public ArrayList<Topic> getTopics(Context context) {
ArrayList<Topic> topics = new ArrayList<>();
String filename = mSubjectIdentifier + "_" + mBoardIdentifier + "_topics.csv";
CsvParser parser = CsvUtils.getMyParser();
try {
List<String[]> allRows = parser.parseAll(context.getAssets().open(filename));
for (String[] line : allRows) {
int id = Integer.parseInt(line[0]);
topics.add(new CourseTopic(id, line[1], line[2], this));
}
} catch (IOException e) {
e.printStackTrace();
}
return topics;
}
...
protected Course(Parcel in) {
mSubjectIdentifier = in.readString();
mBoardIdentifier = in.readString();
mCourseType = in.readString();
mRevisionGuide = in.readString();
}
public static final Creator<Course> CREATOR = new Creator<Course>() {
@Override
public Course createFromParcel(Parcel in) {
return new Course(in);
}
@Override
public Course[] newArray(int size) {
return new Course[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mSubjectIdentifier);
dest.writeString(mBoardIdentifier);
dest.writeString(mCourseType);
dest.writeString(mRevisionGuide);
}
:
onCreate(...)
Course.java - Bundle extras = getIntent().getExtras();
extras.setClassLoader(Topic.class.getClassLoader());
mTopic = extras.getParcelable(EXTRA_TOPIC);
:
writeToParcel(...)
Course.java - dest.writeString(mSubjectIdentifier);
dest.writeString(mBoardIdentifier);
dest.writeString(mCourseType);
dest.writeInt(mRevisionGuide == null ? 0 : 1);
if (mRevisionGuide != null) dest.writeString(mRevisionGuide);
:
Course(Parcel in)
我使用mSubjectIdentifier = in.readString();
mBoardIdentifier = in.readString();
mCourseType = in.readString();
if (in.readInt() != 0) mRevisionGuide = in.readString();
添加了日志消息,以查看在Log.d(...)
中传递任何变量是否为空,并使用 David Wasser 的方法来正确处理此问题。
但是我仍然会收到相同的错误消息。
答案 0 :(得分:23)
您的问题出在LanguagesFlashCard
。以下是您的parcel / unparcel方法:
protected LanguagesFlashCard(Parcel in) {
mId = in.readInt();
mEnglish = in.readString();
mAnswerPrefix = in.readString();
mAnswer = in.readString();
mTier = in.readInt();
mTopic = in.readParcelable(Topic.class.getClassLoader());
}
如您所见,它们不匹配。您写给Parcel
的第二项是int
,您从Parcel
读取的第二项是String
。
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mId);
dest.writeInt(mTier);
dest.writeString(mEnglish);
dest.writeString(mAnswerPrefix);
dest.writeString(mAnswer);
dest.writeParcelable(mTopic, flags);
}
答案 1 :(得分:0)
用于子数据类(如ImagesModel)的Kotlin代码也可打包使用
data class MyPostModel(
@SerializedName("post_id") val post_id: String? = "",
@SerializedName("images") val images: ArrayList<ImagesModel>? = null
): Parcelable {
constructor(parcel: Parcel) : this(
parcel.writeString(post_id)
parcel.createTypedArrayList(ImagesModel.CREATOR)
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(post_id)
parcel.writeTypedList(images)
}
}