2013-08-08 9 views
39

एक कस्टम वर्ग org.example.app.MyClass implements Parcelable को देखते हुए के रूप में एक classloader है कि का उपयोग करते समय, मैं एक पार्सल करने के लिए एक List<MyClass> लिखना चाहते हैं। जब भी मैं"BadParcelableException: ClassNotFoundException जब <myclass> unmarshalling" Parcel.read विधि तर्क

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

साथ वर्ग unmarshall के लिए एक "BadParcelableException: ClassNotFoundException when unmarshalling org.example.app.MyClass" अपवाद नहीं है की कोशिश मैं

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

साथ मार्शलिंग किया था।

यहां क्या गलत है? कक्षा क्यों नहीं मिली है?

+1

मुझे यह त्रुटि एक अलग संदर्भ में मिली - एक बंडल पर 'bundle.keySet()' को कॉल करना जिसमें पार्ससेल योग्य था। प्रश्न में कोड के खिलाफ एक व्यक्तिगत टेस्ट क्लास चलाते समय, यह पारित हो गया, लेकिन पूरे टेस्ट सूट को चलाने से 'BadParcelableException' में परिणाम हुआ। "फिक्स" 'bundle.setClassloader (MyClass.class.getClassLoader()) 'bundle.keySet()' से पहले था। –

उत्तर

84

क्लासलोडर तर्क के रूप में null को जब आप null देते हैं तो फ्रेमवर्क क्लास लोडर के साथ, एंड्रॉइड फ्रेमवर्क द्वारा आपके एप्लिकेशन द्वारा प्रदान की गई एक कस्टम क्लास को अनारशेल न करें। आवेदन वर्ग लोडर का उपयोग करें:

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

जब भी कोई Parcel.read*() विधि भी तर्क के रूप में एक classloader है (उदाहरण के लिए Parcel.readList(List outVal, ClassLoader loader)) और आप एक Parcel से एक आवेदन वर्ग पढ़ा आवेदन वर्ग लोडर कि getClass().getClassLoader() के साथ प्राप्त किया जा सकता है का उपयोग करना चाहते ।

पृष्ठभूमि: एंड्रॉइड दो क्लास लोडर के साथ आता है: सिस्टम क्लास लोडर, जो सभी सिस्टम कक्षाओं को लोड करने में सक्षम है लेकिन आपके आवेदन द्वारा प्रदान किए गए हैं। और एप्लिकेशन क्लास लोडर, जिसने सिस्टम क्लास लोडर को माता-पिता के रूप में सेट किया है और इसलिए सभी वर्गों को लोड करने में सक्षम है। यदि आप ClassNotFoundException में कारण बनाते हैं, तो आप कक्षा लोडर, Parcel.readParcelableCreator(), will use the framework class loader को शून्य देते हैं।

है कि मुझे सही रास्ते पर ले जाते हैं the hint प्रदान करने के लिए alexanderblom के लिए धन्यवाद

16

मेरा मानना ​​है कि इस का एक और अधिक सही रूप होगा:

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

यहाँ क्योंकि आप स्पष्ट रूप से वर्ग लोडर उपयोग कर रहे हैं सूची के सामान्य प्रकार के लिए।

+6

यह मूल रूप से मेरे उत्तर के समान है। 'MyClass.class' और' getClass() 'के बीच कोई अंतर नहीं है, दोनों ही क्लास ऑब्जेक्ट को वापस करते हैं क्योंकि MyClass के भीतर' getClass() 'कहा जाता है। साथ ही, आप यहां किसी भी वर्ग का उपयोग कर सकते हैं, जब तक कि यह एक कस्टम वर्ग है और ढांचे द्वारा प्रदान नहीं किया गया है। – 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 बॉयलरप्लेट (किसी अन्य वर्ग या एक टेम्पलेट से नकल) के गलत क्रियान्वयन इस प्रकार दिखाई देगा:

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 से superstate के रूप में काम नहीं होता एक classloader की आवश्यकता है। इसके बजाय आप ध्यान से BottomNavigationView से SavedState वर्ग का निरीक्षण किया और सही ClassLoaderCreator बल्कि Creator से उपयोग करना चाहिए: 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); 
    } 
} 

नोट विस्तार android.support.v4.view.AbsSavedState हो सकता है कि क्योंकि यह आप के लिए एक वर्ग लोडर पारित करने के लिए अनुमति देगा सुपरक्लास:

SavedState(Parcel source, ClassLoader classLoader) { 
    super(source, classLoader); //available in android.support.v4.view.AbsSavedState 
    this.stateBundle = source.readBundle(classLoader); 
} 
संबंधित मुद्दे