Soru Bağımsız değişken olarak bir ClassLoader olan Parcel.read yöntemini kullanırken “BadParcelableException: ClassNotFoundException unmarshalling


Özel bir sınıf verildiğinde org.example.app.MyClass implements ParcelableYazmak istiyorum List<MyClass> bir parsele. İle marshalling yaptım

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

ne zaman sınıf ile unshashall denemek

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

orada bir "BadParcelableException: ClassNotFoundException when unmarshalling org.example.app.MyClass" istisna.

Burada sorun nedir? Sınıf neden bulunamadı?


44
2017-08-08 12:38


Menşei


Bu hatayı farklı bir bağlamda aldım bundle.keySet() Parcelable içeren bir paket üzerinde. Söz konusu koda karşı bireysel bir test dersi çalıştırırken geçti, ancak tüm Test paketinin çalıştırılmasıyla sonuçlandı. BadParcelableException. "Fix" yapmaktı bundle.setClassloader(MyClass.class.getClassLoader()) önce bundle.keySet(). - Stan Kurdziel


Cevaplar:


Verdiğinizde kullanılan çerçeve sınıfı yükleyiciyle, Android çerçevesine göre değil, uygulamanız tarafından sağlanan özel bir sınıfın seçimini kaldırmayın. null Classloader argümanı olarak. Uygulama sınıfı yükleyiciyi kullanın:

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

Ne zaman bir Parcel.read*() yöntem ayrıca argüman olarak bir ClassLoader'a (ör. Parcel.readList(List outVal, ClassLoader loader)) ve bir uygulama sınıfını bir Parcelile alınabilecek uygulama sınıfı yükleyiciyi kullanın getClass().getClassLoader().

Arka fon: Android, iki sınıf yükleyiciyle birlikte gelir: Sistem sınıfı yükleyici, tüm sistem sınıflarını yükleyebilir, ancak uygulamanız tarafından sağlananları yükleyebilir. Ve sistem sınıfı yükleyiciyi ebeveyn olarak ayarlayan ve böylece tüm sınıfları yükleyebilen uygulama sınıfı yükleyici. Eğer boş bir sınıf yükleyici verirseniz, Parcel.readParcelableCreator(), çerçeve sınıfı yükleyiciyi kullanacak, neden ClassNotFoundException.

Sağlamak için alexanderblom için teşekkürler ipucu Bu beni doğru yolda yönlendiriyor


92
2017-08-08 12:38





Bunun daha doğru bir biçimi olduğuna inanıyorum:

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

Çünkü burada List'in jenerik türü için sınıf yükleyicisini açıkça kullanıyorsunuz.


17
2018-01-29 07:22



Bu benim cevabımla aynı. Arasında fark yoktur MyClass.class ve getClass(), her ikisi de aynı sınıf nesnesini döndürür getClass() MyClass içinde çağrılır. Ayrıca, herhangi bir sınıfı, özel bir sınıf olduğu ve çerçeve tarafından sağlanmadığı sürece kullanabilirsiniz. - Flow
Yanlış olduğunu söylemedim, sadece bu form daha uygun olabilirdi. Ayrıca, ek bir yöntem çağrısı yaptığınızı düşünün. getClass() Bu, sınıfa statik olarak başvurduğunuzda gerekli değildir. - Tanner Perrien


Aynı problemle karşılaştım ve paketlenebilir yerine paket kullanıyorum

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

intent.putExtra("bundle",bundle);

Ve niyet sınıfımda, değeri almak için bunu kullandım:

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

Umarım bazılarına yardımcı olur.


4
2017-09-12 13:31





Özel bir Görünümü yanlış bir şekilde alt sınıf olarak sınıflandırırsanız bu hatayı alabilirsiniz.

Alt sınıf olduğunuzu varsayın BottomNavigationView ve kaydedilen durumu onSaveInstanceState().

Parcelable boilerplate'in (başka bir sınıftan veya şablondan kopyalanan) yanlış bir uygulaması şöyle görünecektir:

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

Bu süperstat olarak işe yaramazdı BottomNavigationView bir sınıf yükleyicisi gerektirir. Bunun yerine dikkatli bir şekilde incelemeniz gerekir. SavedState sınıftan BottomNavigationView ve doğru kullanın ClassLoaderCreator ziyade 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);
    }
}

Uzatmak unutmayın android.support.v4.view.AbsSavedState daha iyi bir seçim olabilir BaseSavedState veya android.view.AbsSavedState bir sınıf yükleyiciyi süper sınıfa geçirmenize izin vereceğinden:

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



Merhaba David Rawson, cevabınız için çok teşekkürler. Bu benim genişletilmiş BottomNavigationView ile benim durumum. - temnoi