2015-08-24 10 views
12

Ho un'applicazione Android in cui aggiungo un altro enum:Android "java.lang.RuntimeException: Parcelable encounteredClassNotFoundException lettura di un oggetto Serializable"

public enum RootNavigationOption { 
    HOME(R.string.home, R.drawable.ic_home), SETTINGS(R.string.settings, R.drawable.ic_settings), LOGOUT(
      R.string.logout_label, R.drawable.ic_logout); 

    private int navigationOptionLabelResId; 
    private int navigationOptionImageResId; 

    private RootNavigationOption(int navigationOptionLabelResId, int navigationOptionImageResId) { 

     this.navigationOptionLabelResId = navigationOptionLabelResId; 
     this.navigationOptionImageResId = navigationOptionImageResId; 
    } 

    public int getNavigationOptionLabelResId() { 
     return navigationOptionLabelResId; 
    } 

    public int getNavigationOptionImageResId() { 
     return navigationOptionImageResId; 
    } 

    public static int getValuePosition(RootNavigationOption filterOption) { 
     int idx = 0; 
     for (RootNavigationOption navigationOptionIter : values()) { 
      if (navigationOptionIter.equals(filterOption)) { 
       return idx; 
      } 
      idx++; 
     } 
     return 0; 
    } 
} 

ho messo in questo enum e lo mise in un paio di intenti pacchetti per la comunicazione alla mia attività principale. Ho già uno di questi enum nella mia soluzione, che non causa alcun problema. Tuttavia, quando faccio funzionare la mia applicazione con questa nuova enum in fase di definizione, si blocca immediatamente con:

java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object (name = com.pack1.pack2.pack3.helpers.RootNavigationOption) 
    at android.os.Parcel.readSerializable(Parcel.java:2219) 
    at android.os.Parcel.readValue(Parcel.java:2064) 
    at android.os.Parcel.readArrayMapInternal(Parcel.java:2314) 
    at android.os.Bundle.unparcel(Bundle.java:249) 
    at android.os.Bundle.getString(Bundle.java:1118) 
    at android.app.ActivityOptions.<init>(ActivityOptions.java:310) 
    at com.android.server.am.ActivityRecord.updateOptionsLocked(ActivityRecord.java:668) 
    at com.android.server.am.ActivityStack.startActivityLocked(ActivityStack.java:1778) 
    at com.android.server.am.ActivityStackSupervisor.startActivityUncheckedLocked(ActivityStackSupervisor.java:1769) 
    at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1249) 
    at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:741) 
    at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3118) 
    at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3104) 
    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:135) 
    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2071) 
    at android.os.Binder.execTransact(Binder.java:404) 
    at dalvik.system.NativeStart.run(Native Method) 
Caused by: java.lang.ClassNotFoundException: com.pack1.pack2.pack3.helpers.RootNavigationOption 
    at java.lang.Class.classForName(Native Method) 
    at java.lang.Class.forName(Class.java:251) 
    at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2262) 
    at java.io.ObjectInputStream.readEnumDescInternal(ObjectInputStream.java:1553) 
    at java.io.ObjectInputStream.readEnumDesc(ObjectInputStream.java:1534) 
    at java.io.ObjectInputStream.readEnum(ObjectInputStream.java:1579) 
    at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:768) 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1981) 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1938) 
    at android.os.Parcel.readSerializable(Parcel.java:2213) 
    ... 16 more 
Caused by: java.lang.NoClassDefFoundError: com/pack1/pack2/pack3/helpers/RootNavigationOption 
    ... 26 more 
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.pack1.pack2.pack3.helpers.RootNavigationOption" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib]] 
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:497) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:457) 
    ... 26 more 

io non sono in grado di trovare il casue radice del problema. Ho anche preso in considerazione i seguenti post, senza alcun risultato:

  • post1 - Non sto utilizzando alcun caricatore cusotm.
  • post2 - sto eseguendo l'applicazione direttamente da ADT, nessun proguard coinvolto.

anche io ho:

  • controllato il mio classi nella cartella bin e la classe necessaria è in là.
  • decompilato l'apk pronto con apktool e la rispettiva Smali è anche lì

EDIT

Ora sono assolutamente certo che l'eccezione è effettivamente causato da mettendo il valore enum in un fascio utilizzato per iniziare l'attività, anche se queste righe non sono menzionati nel stacktrace:

Bundle activityOptions = new Bundle(); 
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME); 
Intent intent = new Intent(this, MainActivity.class); 

ho cambiato la logica della mia domanda non utilizzare questo valore enum in Bundle solo per es. come parametro metodo e ora funziona senza eccezioni. Qualcuno ha la più pallida idea del perché questo accada?

Ho anche messo una taglia sulla domanda ora, perché sono più perplesso.

+0

'sul percorso: DexPathList [ ""[Directory], nativeLibraryDirectories = [/ system/lib]]', ma si dice che la classe memorizzato nella cartella 'bin'? – BNK

+0

Questo è un po 'strano, secondo la documentazione di Enum dice che è serializzabile. http://developer.android.com/reference/java/lang/Enum.html – JoxTraex

+0

@JoxTraex non solo: utilizzo correttamente un altro enum in un pacchetto (ma è un parametro di un frammento) –

risposta

6

Utilizzare semplicemente l'ordinale enum come extra utilizzando Enum.ordinal(); Inoltre, questo dovrebbe rendere il tuo RootNavigationOption.getValuePosition() obsoleto.

Esempio:

final Intent intent = new Intent(this, MainActivity.class); 
intent.putExtra(Constants.VIEW_MODE, RootNavigationOption.SETTINGS.ordinal()); 

avanti nel MainActivity (o simile):

final int defaultViewModeOrdinal = RootNavigationOption.HOME.ordinal(); 
final int viewModeOrdinal = getIntent().getIntExtra(Constants.VIEW_MODE, defaultViewModeOrdinal); 
final RootNavigationOption viewMode = RootNavigationOption.values()[viewModeOrdinal]; 
1

Come ho suggerito nei miei commenti (supponendo che Constants.VIEW_MODE è una chiave String):

//Inside an activity or use getApplicationConext().getClassLoader() 
ClassLoader loader = this.getClassLoader(); 
Bundle activityOptions = new Bundle(loader); 
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME); 

EDIT:

Hmmm..so il costruttore pubblico non funziona come per la documentazione . Scioccante. Forse possiamo forzare un cambiamento utilizzando questo un altro metodo: http://developer.android.com/reference/android/os/Bundle.html#setClassLoader(java.lang.ClassLoader)

Prova a modificare e fatemi sapere cosa succede:

Bundle activityOptions = new Bundle(); 
activityOptions.setClassLoader(RootNavigationOption.class.getClassLoader()); 
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME); 
+0

Grazie per il suggerimento, ma il problema persiste per me. –

+0

@BorisStrandjev vedere la mia risposta modificata, mi rifiuto di arrendermi a questo :) –

+0

Sempre lo stesso risultato, –

2

Sembra che Android stia disaggregando su un altro processo in cui l'intento è passato e ha cercato di essere elaborato, dove il tuo enum non vive; letto oltre: Passing enum or object through an intent (the best solution) per ulteriori informazioni.

+0

Grazie per il collegamento. Puoi speculare sull'altro processo che separa? –

+0

Cosa stai iniziando con l'intento che contiene il pacchetto che causa il problema? –

+0

inizio un'attività –

1

Mentre gli ordinali approccio funziona, vi consiglio di essere più esplicito sui valori. Questo aggiunge un po 'più di codice da implementare, ma rende il tuo codice più leggibile ed esplicito per la protezione da possibili problemi futuri come il riordino o l'inserimento di nuovi valori nel mezzo dell'elenco.

public enum RootNavigationOption { 
    HOME(0, R.string.home, R.drawable.ic_home), 
    SETTINGS(1, R.string.settings, R.drawable.ic_settings), 
    LOGOUT(2, R.string.logout_label, R.drawable.ic_logout); 

    // Note the added code instance variable here, used in the constructor as well. 
    private final int code; 
    private final int navigationOptionLabelResId; 
    private final int navigationOptionImageResId; 

    private RootNavigationOption(int code, 
           int navigationOptionLabelResId, 
           int navigationOptionImageResId) { 
     this.code = code; 
     this.navigationOptionLabelResId = navigationOptionLabelResId; 
     this.navigationOptionImageResId = navigationOptionImageResId; 
    } 

    public int getNavigationOptionLabelResId() { 
     return navigationOptionLabelResId; 
    } 

    public int getNavigationOptionImageResId() { 
     return navigationOptionImageResId; 
    } 

    public int getCode() { 
     return code; 
    } 

    public static RootNavigationOption fromCode(int code) { 
     switch(code) { 
      case 0: 
       return HOME; 
      case 1: 
       return SETTINGS; 
      case 2: 
       return LOGOUT; 
      default: 
       throw new RuntimeException(
        "Illegal RootNavigationOption: " + code); 
     } 
    } 
} 

Questo può quindi essere utilizzato in questo modo:

// Put 
Bundle bundle = new Bundle(); 
bundle.putInt("key", RootNavigationOption.HOME.getCode()); 

// Get 
RootNavigationOption rootNavigationOption = RootNavigationOption.fromCode(bundle.getInt("key")); 
Problemi correlati