简体   繁体   中英

Use of ClassLoader in parcelable.readArrayList() in Android

I've got a Class named as FilterData which implements Parcelable. I had a member variable private ArrayList<String> listPropertyType; When implementing the parcelable interface in my class, parcel.readArrayList(null) ,the parameter is shown as ClassLoader object . With this member variable the FilterData class works as intended. But I wanted to implement a scenario where ClassLoader object is passed to readArrayList() method.

So what I've gathered from the documentation which is unclear about the public ArrayList readArrayList (ClassLoader loader) that if the ArrayList contains non primitive class ,we have to use ClassLoader .

What's the use case in this scenerio of using a ClassLoader and how to use it? I wanted to use the ClassLoader in the following matter. Added a member variable private ArrayList<RandomClass> listRandom; RandomClass randomClass; private ArrayList<RandomClass> listRandom; RandomClass randomClass; to implement this.

My FilterData class holds :

public FilterData(Parcel parcel)
{
    listPropertyType=parcel.readArrayList(null);
    listRandom=parcel.readArrayList(randomClass);
}



 @Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeList(listPropertyType);
    parcel.writeList(listRandom);
}

And my RandomClass is :

public class RandomClass extends ClassLoader{

//this class is for testing classloader in ArrayList in parcelable .readArrayList()

String name;
int age;

public RandomClass(String name, int age) {
    this.name = name;
    this.age = age;
}
}

This implementation doesn't work. So how to use this?

If the array list you're reading from the parcel is subclass you've made, and not a standard java list subclass, or if it contains non-primitive types, you need to pass MyCustomList.class.getClassLoader().

You need to do it this way because parcelables can be inflated everywhere, anytime, so the code must know the ClassLoader required to load it. Most of the time you won't need it because you will be parcelling stuff inside your own app, but it is a good practice.

In fact, you said the list is a simple ArrayList<String> , so you don't need to do anything. It would be different if it was a MyListSubclass<String> , a ArrayList<MyObject> , or an ArrayList<HashMap<Object, Object>> that may contain other subclassed objects. You get the idea.

First of all, if we want to get a class Parcelable , we can use a website www.parcelabler.com . It will generate the syntax of the class. Secondly If we wanted to use an ArrayList of a class of our own. Making a Parcelable class containing the ArrayList won't work. We need to make the custom class Parcelable as well.

If a class that needs to be parcelable contains a member variable ArrayList<String> list; , the class which is generated from the website, should be :

public class MyParcelable implements Parcelable {
ArrayList<String>  list;

public MyParcelable(ArrayList<String> list) {
    this.list = list;
}

protected MyParcelable(Parcel in) {
    if (in.readByte() == 0x01) {
        list = new ArrayList<String>();
        in.readList(list, String.class.getClassLoader());
    } else {
        list = null;
    }
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    if (list == null) {
        dest.writeByte((byte) (0x00));
    } else {
        dest.writeByte((byte) (0x01));
        dest.writeList(list);
    }
}

@SuppressWarnings("unused")
public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {
    @Override
    public MyParcelable createFromParcel(Parcel in) {
        return new MyParcelable(in);
    }

    @Override
    public MyParcelable[] newArray(int size) {
        return new MyParcelable[size];
    }
};

}

And if the Class contains an ArrayList of a class made by us like this ArrayList<DummyClass> list; , the code should be:

public class MyComplexParcelable implements Parcelable {

ArrayList<DummyClass> list;

public MyComplexParcelable(ArrayList<DummyClass> list) {
    this.list = list;
}

@Override
public String toString() {
    return "MyComplexParcelable{" +
            "list=" + list +
            '}';
}

protected MyComplexParcelable(Parcel in) {
    if (in.readByte() == 0x01) {
        list = new ArrayList<DummyClass>();
        in.readList(list, DummyClass.class.getClassLoader());
    } else {
        list = null;
    }
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    if (list == null) {
        dest.writeByte((byte) (0x00));
    } else {
        dest.writeByte((byte) (0x01));
        dest.writeList(list);
    }
}

@SuppressWarnings("unused")
public static final Parcelable.Creator<MyComplexParcelable> CREATOR = new Parcelable.Creator<MyComplexParcelable>() {
    @Override
    public MyComplexParcelable createFromParcel(Parcel in) {
        return new MyComplexParcelable(in);
    }

    @Override
    public MyComplexParcelable[] newArray(int size) {
        return new MyComplexParcelable[size];
    }
};

}

If we compare both cases , there is no difference in the syntax. Both class uses in.readList(list, String.class.getClassLoader()); and in.readList(list, DummyClass.class.getClassLoader()); which uses ClassLoader object of the correspondent classes.

But in the latter case, we need to make the DummyClass parcelable. Like this:

public class DummyClass implements Parcelable {
int age;
String name;

public DummyClass(int age, String name) {
    this.age = age;
    this.name = name;
}

@Override
public String toString() {
    return "DummyClass{" +
            "age=" + age +
            ", name='" + name + '\'' +
            '}';
}

protected DummyClass(Parcel in) {
    age = in.readInt();
    name = in.readString();
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(age);
    dest.writeString(name);
}

@SuppressWarnings("unused")
public static final Parcelable.Creator<DummyClass> CREATOR = new Parcelable.Creator<DummyClass>() {
    @Override
    public DummyClass createFromParcel(Parcel in) {
        return new DummyClass(in);
    }

    @Override
    public DummyClass[] newArray(int size) {
        return new DummyClass[size];
    }
};
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM