सवाल "BadParcelableException: ClassNotFoundException जब uncelshalling " Parcel.read विधि का उपयोग करते समय जिसमें क्लासलोडर तर्क के रूप में है


एक कस्टम वर्ग दिया गया org.example.app.MyClass implements Parcelable, मैं एक लिखना चाहता हूँ List<MyClass> एक पार्सल के लिए। मैंने साथ marshalling किया था

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

जब भी मैं कक्षा को unmarshall करने की कोशिश करता हूँ

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

वहां पर एक "BadParcelableException: ClassNotFoundException when unmarshalling org.example.app.MyClass" अपवाद।

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


44
2017-08-08 12:38


मूल


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


जवाब:


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

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

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

पृष्ठभूमि: एंड्रॉइड दो क्लास लोडर के साथ आता है: सिस्टम क्लास लोडर, जो सभी सिस्टम वर्गों को लोड करने में सक्षम है लेकिन आपके आवेदन द्वारा प्रदान किए गए हैं। और एप्लिकेशन क्लास लोडर, जिसने सिस्टम क्लास लोडर को माता-पिता के रूप में सेट किया है और इसलिए सभी वर्गों को लोड करने में सक्षम है। यदि आप कक्षा लोडर को शून्य देते हैं, Parcel.readParcelableCreator(), ढांचे वर्ग लोडर का उपयोग करेंगे, जिसके कारण में कक्षा में कोई भी अपवाद नही है

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


92
2017-08-08 12:38





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

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

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


17
2018-01-29 07:22



यह मूल रूप से मेरे उत्तर के समान है। बीच कोई अंतर नहीं है MyClass.class तथा getClass(), दोनों एक ही कक्षा वस्तु के बाद से लौटते हैं getClass() MyClass के भीतर बुलाया जाता है। साथ ही, आप यहां किसी भी वर्ग का उपयोग कर सकते हैं, जब तक कि यह एक कस्टम वर्ग है और ढांचे द्वारा प्रदान नहीं किया गया है। - Flow
मैंने यह नहीं कहा कि आप गलत थे, बस यह फ़ॉर्म अधिक उपयुक्त हो सकता है। यह भी मान लें कि आप एक अतिरिक्त विधि कॉल कर रहे हैं getClass() जब आप कक्षा को सांख्यिकीय रूप से संदर्भित करते हैं तो यह आवश्यक नहीं है। - Tanner Perrien


मुझे एक ही समस्या का सामना करना पड़ा है और बदले में मैं बंडल का इस्तेमाल करता हूं

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

उम्मीद है कि यह कुछ के लिए सहायक होगा।


4
2017-09-12 13:31





यदि आप एक कस्टम दृश्य को गलत तरीके से उपclass करते हैं तो आप यह त्रुटि प्राप्त कर सकते हैं।

मान लें कि आप उपclassing हैं BottomNavigationView और आप सहेजे गए राज्य को सुपरस्टेट में जोड़ना चाहते हैं onSaveInstanceState()

पार्सेलबल बॉयलरप्लेट (किसी अन्य वर्ग या टेम्पलेट से कॉपी) का गलत कार्यान्वयन इस तरह दिखेगा:

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 से वर्ग BottomNavigationView और सही का उपयोग करें ClassLoaderCreator बजाय Creator:

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 से बेहतर विकल्प हो सकता है BaseSavedState या android.view.AbsSavedState चूंकि यह आपको सुपरक्लास में क्लास लोडर पास करने की अनुमति देगा:

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

3
2018-01-23 23:19



हाय डेविड रॉसन, आपके उत्तर के लिए बहुत बहुत धन्यवाद। यह विस्तारित BottomNavigationView के साथ बिल्कुल मेरा मामला है। - temnoi