2012-12-21 11 views
13

Per la mia applicazione Android, ottengo diversi errori di riarrangiamento anche se penso di aver fatto tutto ciò che è necessario per salvare e caricare correttamente gli oggetti tramite Parcelable s. Puoi dirmi cosa c'è di sbagliato nel mio codice?Errori di riarrangiamento nell'app per Android con classi parcelable personalizzate

di errore 1:

java.lang.RuntimeException: Unable to start activity ComponentInfo 
Caused by: java.lang.RuntimeException: Parcel [email protected]: Unmarshalling unknown type code 6619241 at offset 1372 
at android.os.Parcel.readValue(Parcel.java:1922) 
at android.os.Parcel.readMapInternal(Parcel.java:2094) 
at android.os.Bundle.unparcel(Bundle.java:223) 
at android.os.Bundle.getParcelable(Bundle.java:1158) 
at android.app.Activity.onCreate(Activity.java:860) 
at my.app.package.PlayComputer.onCreate(PlayComputer.java:1012) 
at android.app.Activity.performCreate(Activity.java:4465) 

Linea 1012 nel MyActivity è la chiamata a super.onCreate(savedInstanceState); in s' onCreate() il Activity.

protected void onSaveInstanceState(Bundle savedInstanceState) { 
    if (myObject == null) { 
     savedInstanceState.putParcelable("myObject", null); 
    } 
    else { 
     savedInstanceState.putParcelable("myObject", myObject); 
    } 
    savedInstanceState.putInt(...); 
    savedInstanceState.putString(...); 
    savedInstanceState.putBoolean(...); 
    super.onSaveInstanceState(savedInstanceState); 
} 

myObject è di classe MyObject che ha i seguenti metodi:

public void writeToParcel(Parcel out, int flags) { 
    out.writeIntArray(...); 
    out.writeInt(...); 
    out.writeStringArray(...); 
    out.writeString(...); 
    out.writeParcelableArray(..., flags); 
} 

public static final Parcelable.Creator<MyObject> CREATOR = new Parcelable.Creator<MyObject>() { 
    public MyObject createFromParcel(Parcel in) { 
     try { 
      if (in == null) { 
       return null; 
      } 
      else { 
       return new MyObject(in); 
      } 
     } 
     catch (Exception e) { 
      return null; 
     } 
    } 
    public MyObject[] newArray(int size) { 
     return new MyObject[size]; 
    } 
}; 

private MyObject(Parcel in) { 
    in.readIntArray(...); 
    ... = in.readInt(); 
    in.readStringArray(...); 
    ... = in.readString(); 
    ... = (OtherObject[]) in.readParcelableArray(OtherObject.class.getClassLoader()); 
} 

Errore 2:

java.lang.RuntimeException: Unable to start activity ComponentInfo 
Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: 
at android.os.Parcel.readParcelable(Parcel.java:1971) 
at android.os.Parcel.readValue(Parcel.java:1859) 
at android.os.Parcel.readMapInternal(Parcel.java:2099) 
at android.os.Bundle.unparcel(Bundle.java:223) 
at android.os.Bundle.getParcelable(Bundle.java:1158) 
at android.app.Activity.onCreate(Activity.java:905) 
at my.app.package.PlayComputer.onCreate(SourceFile:1012) 

stessi file e le classi.

Errore 3:

java.lang.RuntimeException: Unable to start activity ComponentInfo 
Caused by: java.lang.RuntimeException: Parcel [email protected]: Unmarshalling unknown type code 7340149 at offset 1276 
at android.os.Parcel.readValue(Parcel.java:1913) 
at android.os.Parcel.readMapInternal(Parcel.java:2083) 
at android.os.Bundle.unparcel(Bundle.java:208) 
at android.os.Bundle.getParcelable(Bundle.java:1100) 
at my.app.package.PlayComputer.onCreate(SourceFile:1111) 

Questa volta, la linea che causa (1111) è la seguente:

myObject = (MyObject) savedInstanceState.getParcelable("myObject"); 
+0

Il costruttore di GameState (Parcel in) è un errore di battitura e si intendeva scrivere un costruttore MyObject (Parcel in)? – fedepaol

+0

@fedepaol: Sì, mi dispiace! – caw

+0

Stai creando separatamente gli oggetti array nel tuo costruttore? I metodi 'readXXXArray()' richiedono un'istanza dell'array completamente inizializzata da passare. È possibile utilizzare i metodi 'createXXXArray()' per ottenere una nuova istanza di tale array restituita all'utente. – Devunwired

risposta

37

Android ha due diverse classloader: il programma di caricamento classe quadro (che sa come caricare le classi Android) e il programma di caricamento classe APK (che sa come caricare il codice). Il classloader APK ha il classloader framework impostato come genitore, il che significa che può caricare anche le classi Android.

L'errore n. 2 è probabilmente causato dal pacchetto che utilizza il classloader framework in modo che non conosca le classi. Penso che questo possa accadere quando Android ha bisogno di conservare il pacchetto e successivamente ripristinarlo (ad esempio quando si esaurisce la memoria in background). È possibile risolvere questo problema impostando il programma di caricamento classi APK sul pacchetto:

savedInstanceState.setClassLoader (getClass(). GetClassLoader());

Gli errori n. 1 e n. 3 sono più misteriosi, stai forse scrivendo valori nulli in writeToParcel()? Android non mi piace molto, ho paura.

+0

Grazie! 'savedInstanceState.setClassLoader (getClass(). getClassLoader());' sembra buono ma temo di poterlo chiamare solo per una classe. Cosa succede se devo mettere oggetti da più di una classe in quel 'Bundle'? Per quale classe chiamarlo? – caw

+0

Inoltre, con alcune modifiche, sembra come se il problema è risolto ora: http://stackoverflow.com/questions/13997550/unmarshalling-errors-in-android-app-with-custom-parcelable-classes#comment19498428_13997695 si potrebbe immagina che questo modo di leggere gli oggetti sia ciò che ha causato i problemi? – caw

+1

Funzionerà per tutte le classi come getClass(). GetClassLoader() recupererà il classloader APK (che può caricare tutte le classi). Durante la lettura con readXXXArray(), quali array sono stati trasmessi? Come sai che sono della lunghezza corretta? createTypedArray() e altri non scrivono/leggono informazioni sul tipo, il che significa che i programmi di caricamento di classe non sono realmente coinvolti. – alexanderblom

2

Con l'aspetto di essa, il createFromParcel e newArray dovrebbero essere sovrascritti In questo modo:

public static final Parcelable.Creator<MyObject> CREATOR = new Parcelable.Creator<MyObject>() { 
    @Override 
    public MyObject createFromParcel(Parcel in) { 
     MyObject myObj = new MyObject(); 
     myObj.intArray = in.readIntArray(...); 
     myObj.intValue = in.readInt(...); 
     // .... 
     // IN THE SAME ORDER THAT IS WRITTEN OUT AS PER writeToParcel! 
     // 
     return myObj; 
    } 
    @Override 
    public MyObject[] newArray(int size) { 
     return new MyObject[size]; 
    } 
}; 

Modifica:

Ho dimenticato di dire che per il funzionamento di sopra, avrebbe dovuto esserci un costruttore vuoto!

public MyObject(){} 
+0

Grazie! Non è esattamente quello che sto facendo? Sto solo usando il costruttore 'MyObject (in)' per rendere le cose più chiare. Ah ok, forse non l'hai visto a causa del mio errore di battitura nel nome del costruttore, che ora è stato corretto. – caw

+0

L'unica cosa che mi viene in mente, è forse ci dovrebbe essere un costruttore vuoto, hanno modificato la risposta ... – t0mm13b

+0

vi preghiamo di verificare che siete '@ Override' i due metodi' describeContents() 'e' writeToParcel() ':) – t0mm13b

0

Prima lettura dal fascio set ClassLoader

bundle.setClassLoader (getClass().getClassLoader());

questo mi ha salvato il tempo!

Problemi correlati