2016-06-23 17 views
6

Ich bekomme einen seltsamen Fehler in meiner App (siehe GitHub), die auftritt, wenn ich Objekte an verschiedene Aktivitäten übergeben, die Parcelable implementieren.java.lang.RuntimeException: Paket android.os.Parcel: Unmarshalling unbekannter Typ Code

Ich habe andere Fragen und Antworten hier auf Stack Overflow überprüft, aber ich konnte keine Lösung finden. Ich habe die Antwort here versucht, zum Beispiel - hier ist es als Referenz:

-keepclassmembers class * implements android.os.Parcelable { 
    static ** CREATOR; 
} 

ich auch dafür gesorgt haben, dass die Methodenaufrufe in writeToParcel in Ordnung sind. Die meisten anderen Fragen zu Stack Overflow zu diesem Thema haben keine Antworten.

Darüber hinaus ist der Grund, warum ich eine neue Frage stelle, weil ich denke, dass mein Problem verursacht wird, weil ich Schnittstellen in meiner App verwendet habe (ich werde später auf diesen Punkt erweitern). Andere Fragen zu Stack Overflow würden meinem speziellen Szenario nicht gerecht werden.

Im Folgenden habe ich über GitHub Links zum Code bereitgestellt, damit Sie bei Bedarf mehr Code untersuchen können.


Wenn ich auf eine Schaltfläche, um launch a new activity (vorbei an ein Objekt, das Parcelable implementiert), 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 [email protected]: Unmarshalling unknown type code 6815860 at offset 200 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416) 
    ... 
Caused by: java.lang.RuntimeException: Parcel [email protected]: 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) 
... 

ich die oben erwähnte Aktivität nennen wie so (auch 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); 

Der Hauptteil zu betrachten ist, wenn ich mTopic passiere. Dies ist eine Topicinterface, die ich erstellt habe.

jedoch die Topic Schnittstelle erweitert Parcelable und so die Objekte, die Topic umfassen auch den Konstruktor, CREATOR Feld, und die Methoden implementieren, die eine Klasse Parcelable Implementierung normalerweise haben müssen.

Sie können die relevanten Klassen über die GitHub Links sehen, aber ich werde die relevanten Teile dieser Klassen unten zur Verfügung stellen. Hier ist die Topic Schnittstelle:

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

     ... 
    } 

} 

A-Klasse (Objekt), dass 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); 
    } 

} 

In einem der letzten Zeilen des Codes oben können Sie sehen, ich pass mCourse, das ist ein Course Objekt, das ich erstellt habe. Hier ist sie:

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

}

ich etwas vermuten, hier kann das Problem verursacht, und ist der Grund, mein Szenario von denen in anderen Fragen unterscheiden.


Um ehrlich zu sein, ich bin nicht ganz sicher, was den Fehler verursacht sein kann, so Erklärungen und Anleitungen in Antworten sehr geschätzt werden würden.


bearbeiten:

Nach David Wasser ‚s Vorschläge, ich habe Teile meines Code aktualisiert wie folgt:

FlashCardActivity.java - onCreate(...):

Bundle extras = getIntent().getExtras(); 
extras.setClassLoader(Topic.class.getClassLoader()); 
mTopic = extras.getParcelable(EXTRA_TOPIC); 

Course.java - writeToParcel(...):

dest.writeString(mSubjectIdentifier); 
dest.writeString(mBoardIdentifier); 
dest.writeString(mCourseType); 
dest.writeInt(mRevisionGuide == null ? 0 : 1); 
if (mRevisionGuide != null) dest.writeString(mRevisionGuide); 

Course.java - Course(Parcel in):

mSubjectIdentifier = in.readString(); 
mBoardIdentifier = in.readString(); 
mCourseType = in.readString(); 
if (in.readInt() != 0) mRevisionGuide = in.readString(); 

Ich habe Protokollnachrichten hinzugefügt Log.d(...) verwenden, wenn alle Variablen null sind, um zu sehen, wenn sie in writeToParcel(...) und verwendet David Wasser geben wird ‚s Methode richtig geh damit um.

Ich bekomme immer noch die gleiche Fehlermeldung.

+0

Geben Sie den Code für das Parzellieren und Unparceling für die tatsächlichen Klassen ein, die in den 'Intent' geschrieben werden. –

+0

@DavidWasser Ich habe meine Antwort aktualisiert, um den Code für die Klassen anzuzeigen, die in den 'Intent' geschrieben wurden (sie können vollständig über die bereitgestellten GitHub-Links angezeigt werden). –

Antwort

17

Ihr Problem ist in LanguagesFlashCard. Hier sind Ihre Paket/Unparzellen-Methoden:

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

Wie Sie sehen können, stimmen sie nicht überein. Der zweite Artikel, den Sie an die Parcel schreiben, ist ein int, der zweite Artikel, den Sie aus der Parcel lesen, ist ein 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

Danke - das hat mein Problem gelöst! –

+0

Kann sich die Reihenfolge der Werte ändern, wenn alle vom selben Typ sind. Ich meine mEnglish = in.readString(); mAnswerPrefix = in.readString(); mAnswer = in.readString(); kann als dest.writeString (mAnswer) gelesen werden; dest.writeString (mEnglish); dest.writeString (mAnswerPrefix); –

+1

@UsmanRana Nein. Sie müssen die Werte in genau der gleichen Reihenfolge lesen und schreiben, unabhängig davon, um welche Typen es sich handelt. Sie serialisieren und deserialisieren zu/von einem Bytearray. 'Paket' ist keine' HashMap'. –