2016-06-23 20 views
6

Sembra che si verifichi uno strano errore nella mia app (vedere GitHub), che si verifica quando si passano oggetti a diverse attività che implementano Parcelable.java.lang.RuntimeException: Parcel android.os.Parcel: codice sconosciuto codice sconosciuto

Ho controllato altre domande e risposte qui su Stack Overflow, ma non sono riuscito a trovare una soluzione. Ho provato la risposta here, per esempio - qui è per riferimento:

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

Ho anche fatto in modo che il metodo chiama writeToParcel sono in ordine. La maggior parte delle altre domande su Stack Overflow relative a questo problema non hanno risposte.

Inoltre, il motivo per cui sto facendo una nuova domanda è perché penso che il mio problema sia causato da come ho usato le interfacce nella mia app (mi dilungherò su questo punto in seguito). Altre domande su Stack Overflow non si adattano al mio particolare scenario.

Di seguito, ho fornito collegamenti al codice tramite GitHub, in modo che sia possibile esplorare più del codice, se necessario.


Quando scatto sopra un pulsante per launch a new activity (passaggio di un oggetto che implementa 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 [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) 
... 

io chiamo dell'attività citata in questo modo (anche 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); 

La parte principale da considerare è quando passo mTopic. Questo è un Topicinterface che ho creato.

Tuttavia, l'interfaccia Topic estende Parcelable e così gli oggetti che implementano Topic includono anche il costruttore, CREATOR campo, ei metodi che una classe che implementa Parcelable normalmente dovrebbe avere.

È possibile visualizzare le classi rilevanti tramite i collegamenti GitHub, ma fornirò le parti pertinenti di queste classi di seguito. Qui è l'interfaccia 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; 
     } 

     ... 
    } 

} 

una classe (oggetto) che 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 una delle ultime righe del codice di cui sopra, si può vedere che passo mCourse, che è un Course oggetto che ho creato. Eccolo:

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

}

Ho il sospetto che qualcosa qui potrebbero essere la causa del problema, ed è il motivo per il mio scenario è diverso da quelli di altre questioni.


Per essere onesti, io non sono esattamente sicuro di quello che potrebbe essere causa l'errore, in modo da spiegazioni e guida in risposte sarebbe molto apprezzato.


Edit:

Dopo suggerimenti David Wasser s', ho aggiornato le parti del mio codice in questo modo:

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

Ho aggiunto i messaggi di log utilizzando Log.d(...) per vedere se tutte le variabili sono nulli quando viene passato in writeToParcel(...) e utilizzato il metodo David Wasser s' correttamente gestire questo.

Ho ancora lo stesso messaggio di errore, tuttavia.

+0

Inviare il codice relativo alla parcel e alla non assegnazione per le classi effettive immesse nell'intento. –

+0

@DavidWasser Ho aggiornato la mia risposta per mostrare il codice per le classi inserite nell '"Intento" (possono essere visualizzate integralmente tramite i link GitHub forniti). –

risposta

17

Il tuo problema è LanguagesFlashCard. Ecco i vostri metodi pacchi/disaccordi:

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

Come potete vedere, non corrispondono. Il secondo elemento che scrivi sullo Parcel è un int, il secondo elemento letto dallo Parcel è un 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

Grazie - questo ha risolto il mio problema! –

+0

L'ordine dei valori può cambiare, se tutti sono dello stesso tipo. Intendo mEnglish = in.readString(); mAnswerPrefix = in.readString(); mAnswer = in.readString(); può essere letto come dest.writeString (mAnswer); dest.writeString (mEnglish); dest.writeString (mAnswerPrefix); –

+1

@UsmanRana No. È necessario leggere e scrivere i valori esattamente nella stessa sequenza, indipendentemente dal loro tipo. Si sta serializzando e deserializzando da/verso un array di byte. 'Parcel' non è un' HashMap'. –

Problemi correlati