2013-08-08 14 views
39

カスタムクラスorg.example.app.MyClass implements Parcelableが与えられた場合、List<MyClass>をParcelに書きたいと思います。私は"BadParcelableException: ClassNotFoundException when unmarshalling org.example.app.MyClass"例外があるClassLoaderを引数として持つParcel.readメソッドを使用しているときに、BadParcelableException:ClassNotFoundExceptionをアンマーシャリングするとき

List<MyClass> myclassList = new ArrayList<MyClass>(); 
parcel.readList(myclassList, null); 

を持つクラスをアンマーシャリングしようとするたびに私は

List<MyClass> myclassList = ... 
parcel.writeList(myclassList); 

でマーシャリングを行いました。

ここで何が間違っていますか?なぜクラスが見つからないのですか?

+1

このエラーは別のコンテキストで発生しました。つまり、Parcelableを含むバンドルで 'bundle.keySet()'を呼び出しました。問題のコードに対して個々のテストクラスを実行すると、そのクラスは合格しましたが、テストスイート全体を実行すると 'BadParcelableException'が発生しました。 "修正"は 'bundle.keySet()'の前に 'bundle.setClassloader(MyClass.class.getClassLoader())'を実行することでした。 –

答えて

84

nullにClassloader引数として指定したときに使用されるフレームワーククラスローダーを使用して、アプリケーションが提供するカスタムクラス(Androidフレームワークではなくカスタムクラス)をアンマーシャリングしないでください。 Parcel.read*()方法はまた、引数(例えばParcel.readList(List outVal, ClassLoader loader))としてClassLoaderを持つたび

parcel.readList(myclassList, getClass().getClassLoader()); 

、あなたはParcelからアプリケーションクラスを読みたい、getClass().getClassLoader()で取得することができるアプリケーションクラスローダを使用します。アプリケーション・クラス・ローダーを使用します。

背景: Androidには2つのクラスローダーが付属しています。システムクラスローダーは、すべてのシステムクラスをロードできますが、アプリケーションによって提供されるものです。また、アプリケーションクラスローダーは、システムクラスローダーを親クラスとして設定しているため、すべてのクラスをロードできます。 nullをクラスローダーに指定した場合、Parcel.readParcelableCreator()will use the framework class loaderClassNotFoundExceptionが発生します。右のトラックに私を導くthe hintを提供するためのalexanderblomへ

おかげ

16

私はこれのより正確な形があることと考えている:

List<MyClass> myclassList = new ArrayList<MyClass>(); 
parcel.readList(myclassList, MyClass.class.getClassLoader()); 

ここに明示的にクラスローダを使用しているためListのジェネリック型です。

+6

これは基本的に私の答えと同じです。 'MyClass.class'と' getClass() 'の間に違いはなく、' getClass() 'がMyClass内で呼び出されているので、どちらも同じクラスオブジェクトを返します。また、カスタムクラスであり、フレームワークで提供されていないクラスであれば、ここで任意のクラスを使用できます。 – Flow

+6

私はあなたが間違っているとは言っていませんでした。ちょうどこのフォームがより適切かもしれません。また、クラスを静的に参照するときに不要な 'getClass()'メソッドを追加メソッド呼び出ししていると考えてください。 –

3

私は同じ問題に直面しているし、代わりにparcleableの私は、バンドル

intent.setExtrasClassLoader(getClassLoader()); 
/* Send optional extras */ 
Bundle bundle = new Bundle(); 
bundle.putParcelable("object", mObject); 
bundle.putString("stringVal", stringVal); 

intent.putExtra("bundle",bundle); 

を使用し、私の意思のクラスで私は値を取得するためにこれを使用:

Bundle oldBundle = intent.getBundleExtra("bundle"); 
ResultReceiver receiver = oldBundle.getParcelable("object"); 
String stringVal = oldBundle.getString("stringVal"); 
intent.setExtrasClassLoader(getClassLoader()); 

はそれがために役立つことを願っています一部。

0

カスタムビューを間違ってサブクラス化すると、このエラーが発生する可能性があります。

BottomNavigationViewをサブクラス化し、onSaveInstanceState()のスーパーステートに保存済み状態を追加するとします。

(他のクラスやテンプレートからコピー)Parcelableの決まり文句の間違った実装は次のようになります。BottomNavigationViewからスーパーステートは、クラスローダを必要とする

static class State extends BaseSavedState { 

    Bundle stateBundle; 

    //incorrect as super state uses ClassLoaderCreator 
    public static final Creator<State> CREATOR = new Creator<State>() { 
     public State createFromParcel(Parcel in) { 
      return new State(in); 
     } 

     public State[] newArray(int size) { 
      return new State[size]; 
     } 
    }; 

    State(Parcel source) { 
     super(source); 
     this.stateBundle = source.readBundle(getClass().getClassLoader()); 
    } 

    State(Parcelable superState) { 
     super(superState); 
    } 

    @Override 
    public void writeToParcel(Parcel out, int flags) { 
     super.writeToParcel(out, flags); 
     out.writeBundle(stateBundle); 
    } 
} 

これは動作しないでしょう。代わりに、あなたは慎重にBottomNavigationViewからSavedStateクラスを検査し、正しいClassLoaderCreatorではなくCreatorを使用する必要があります。それはあなたがクラスローダを渡すことができるようになりますので、android.support.v4.view.AbsSavedStateを延びるBaseSavedStateまたはandroid.view.AbsSavedStateより良い選択であってもよいこと

static class State extends AbsSavedState { 

    Bundle stateBundle; 

    public static final Creator<State> CREATOR = new ClassLoaderCreator<State>() { 
     public State createFromParcel(Parcel in, ClassLoader classLoader) { 
      return new State(in, classLoader); 
     } 

     @Override 
     public State createFromParcel(Parcel source) { 
      return new State(source, null); 
     } 

     public State[] newArray(int size) { 
      return new State[size]; 
     } 
    }; 

    State(Parcel source, ClassLoader classLoader) { 
     super(source, classLoader); 
     this.stateBundle = source.readBundle(classLoader); 
    } 

    State(Parcelable superState) { 
     super(superState); 
    } 

    @Override 
    public void writeToParcel(Parcel out, int flags) { 
     super.writeToParcel(out, flags); 
     out.writeBundle(stateBundle); 
    } 
} 

注意をスーパークラス:

SavedState(Parcel source, ClassLoader classLoader) { 
    super(source, classLoader); //available in android.support.v4.view.AbsSavedState 
    this.stateBundle = source.readBundle(classLoader); 
} 
関連する問題