I am trying to create a Parcelable class. The class extends TableRow:
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.widget.TableRow;
public class AcmTableRow extends TableRow implements Parcelable{
private int index;
public boolean isSection;
private String volumeLink;
private String rowId;
private String cfr;
private static Context context;
public AcmTableRow(Context context) {
super(context);
}
public AcmTableRow(Context context, Parcel in) {
super(context);
AcmTableRow.context = context;
readFromParcel(in);
}
private void readFromParcel(Parcel in) {
//strValue = in.readString();
//intValue = in.readInt();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
//dest.writeString(strValue);
//dest.writeInt(intValue);
}
public void setIndex(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public void setRowId(String rowId) {
this.rowId = rowId;
}
public String getRowId() {
return rowId;
}
public void setCfr(String cfr) {
this.cfr = cfr;
}
public String getCfr() {
return cfr;
}
public void setVolumeLink(String volumeLink) {
this.volumeLink = volumeLink;
}
public String getVolumeLink() {
return volumeLink;
}
public static final Parcelable.Creator<AcmTableRow> CREATOR = new Parcelable.Creator<AcmTableRow>() {
public AcmTableRow createFromParcel(Parcel in) {
return new AcmTableRow(context, in);
}
public AcmTableRow[] newArray(int size) {
return new AcmTableRow[size];
}
};
}
I am confused as what I need to put in:
readFromParcel(Parcel in)
And
writeToParcel(Parcel dest, int flags)
Any explanation or help is greatly appreciated.
Thank you
Phil
The writeToParcel method simply flattens the object into a parcel. You'll use this when you need to pass your object between activities. In your case, it should look like this:
public void writeToParcel (Parcel dest, int flags)
{
dest.writeInt(index);
dest.writeBoolean(isSection);
dest.writeString(volumeLink);
dest.writeString(rowId);
dest.writeString(cfr);
}
I've never had to use readFromParcel and I'm not sure you need to here either. Your object will be created from the Parcel when you call the appropriate method in your next activity.
Just a quick note, you probably don't want to pass the context in your parcelable class. I'm not even sure you can. You'll need to assign the context when you inflate the parcelable again later on.
This is a simple working Parcelable example:
public class ParcelableExample implements Parcelable {
private int intMember;
private String stringMember;
/*
* Getters and setters
* ....
*/
/*
* Constructors
* ....
*/
/*
* Custom parcelable implementation
*/
private ParcelableExample(Parcel in) {
// notice that we are reading in the same order as we have written
intMember = in.readInt();
stringMember = in.readString();
}
#Override
public int describeContents() {
return hashCode();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(intMember);
dest.writeString(stringMember);
}
#SuppressWarnings("rawtypes")
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public ParcelableExample createFromParcel(Parcel in) {
return new ParcelableExample(in);
}
public ParcelableExample[] newArray(int size) {
return new ParcelableExample[size];
}
}
Related
I'm trying to pass an ArrayList of unknown class type that extend an abstract class, to another activity using Parcelable. Since its not possible to use Parcelable.CREATOR on the abstract class, there is an error when I try to create the ArrayList: in.readTypedList(AbstractChannel.CREATOR), see below:
public class TvNetwork implements Parcelable {
public String name;
public ArrayList<? extends AbstractChannel> mChannels;
public TvNetwork(String name, ArrayList<? extends AbstractChannel> channels) {
this.name = name;
this.mChannels = channels;
}
protected TvNetwork(Parcel in) {
name = in.readString();
mChannels = in.readTypedList(AbstractChannel.CREATOR); // here is the error
}
public static final Creator<TvNetwork> CREATOR = new Creator<TvNetwork>() {
#Override
public TvNetwork createFromParcel(Parcel in) {
return new TvNetwork(in);
}
#Override
public TvNetwork[] newArray(int size) {
return new TvNetwork[size];
}
};
public ArrayList<? extends AbstractChannel> getChannels() {
return mChannels;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeTypedList(mChannels);
}
}
Writing seems to work but not reading. This obviously does not work either, but explains a bit more what I want to do:
in.readTypedList(mChannels, <? extends AbstractChannel>.class.getClassLoader());
Any ideas?
for my android app i want to use the parcelable interface to save the data when the app is in brackground. I have 3 Float-Values in my class.
It works but when i wake up my app, the values are mixed. That means the value of the third float attribute is now in the first and so on.
Here is my Pojo Lunch.java:
public class Lunch implements Parcelable {
private String mName;
private float priceStud;
private float priceEmp;
private float priceGuest;
private ArrayList<Lunch> m = new ArrayList<Lunch>();
public static final int PRICE_STUDENT = 0;
public static final int PRICE_EMPLOYEE = 1;
public static int PRICE_GUEST = 2;
public Lunch(Parcel in) {
setmName(in.readString());
setPriceStud(in.readFloat());
setPriceEmp(in.readFloat());
setPriceGuest(in.readFloat());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getmName());
dest.writeFloat(getPriceGuest());
dest.writeFloat(getPriceEmp());
dest.writeFloat(getPriceStud());
}
public static final Creator<Lunch> CREATOR = new Creator<Lunch>() {
public Lunch createFromParcel(Parcel in) {
return new Lunch(in);
}
public Lunch[] newArray(int size) {
return new Lunch[size];
}
};
As Durandal said, you need to specify the exact order in which you want to retrieve them when you access the parcel. I think this is what would solve the problem in your case.
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getmName());
dest.writeFloat(getPriceStud());
dest.writeFloat(getPriceEmp());
dest.writeFloat(getPriceGuest());
}
I had Parcelable enum like this:
public enum Option implements Parcelable {
DATA_BASE, TRIPS, BIG_PHOTOS,
OLD_PHOTOS, FILTERS_IMAGES,
CATEGORIES_IMAGES, PAGES,
SOUNDS, PUBLIC_TRANSPORT, MAPS;
public static final Parcelable.Creator<Option> CREATOR = new Parcelable.Creator<Option>() {
public Option createFromParcel(Parcel in) {
return Option.values()[in.readInt()];
}
public Option[] newArray(int size) {
return new Option[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(ordinal());
}
}
Now I modified it and it looks like:
public enum Option implements Parcelable {
DATA_BASE("Database"), TRIPS("Trips"), BIG_PHOTOS("BigPhotos"),
OLD_PHOTOS("OldPhotos"), FILTERS_IMAGES("FiltersImages"),
CATEGORIES_IMAGES("CategoriesImages"), PAGES("Pages"),
SOUNDS("Sounds"), PUBLIC_TRANSPORT("PublicTransport"), MAPS("Maps");
private String option;
Option(String option){
this.option = option;
}
public String getName(){
return option;
}
public static final Parcelable.Creator<Option> CREATOR = new Parcelable.Creator<Option>() {
public Option createFromParcel(Parcel in) {
//...
}
public Option[] newArray(int size) {
//...
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
//...
}
}
How should I implement writeToParcel(), createFromParcel() and newArray() int this Enum? I need that to pass it through extra in intent.
This is an old question but there is a better solution:
dest.writeString(myEnumOption.name());
and
myEnumOption = MyEnum.valueOf(in.readString());
I solved it by:
public enum Option implements Parcelable {
DATA_BASE("Database"), TRIPS("Trips"), BIG_PHOTOS("BigPhotos"),
OLD_PHOTOS("OldPhotos"), FILTERS_IMAGES("FiltersImages"),
CATEGORIES_IMAGES("CategoriesImages"), PAGES("Pages"),
SOUNDS("Sounds"), PUBLIC_TRANSPORT("PublicTransport"), MAPS("Maps");
private String option;
Option(String option){
this.option = option;
}
public String getName(){
return option;
}
private void setOption(String option){
this.option = option;
}
public static final Parcelable.Creator<Option> CREATOR = new Parcelable.Creator<Option>() {
public Option createFromParcel(Parcel in) {
Option option = Option.values()[in.readInt()];
option.setOption(in.readString());
return option;
}
public Option[] newArray(int size) {
return new Option[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(ordinal());
out.writeString(option);
}
}
It may be late for the OP, but it may help others, so I'll still post this.
As it was mentioned before, it's a bad practice to have a setter to an enum's member. If you need that member, make it final (which excludes the possibility of a setter for it)
You don't need to save that member (in your case the String 'option') into the Parcel and restore it on recreation.
My implementation would be as follows
public enum Option implements Parcelable {
DATA_BASE("Database"), TRIPS("Trips"), BIG_PHOTOS("BigPhotos"),
OLD_PHOTOS("OldPhotos"), FILTERS_IMAGES("FiltersImages"),
CATEGORIES_IMAGES("CategoriesImages"), PAGES("Pages"),
SOUNDS("Sounds"), PUBLIC_TRANSPORT("PublicTransport"), MAPS("Maps");
private final String option;
Option(String option){
this.option = option;
}
public String getName() {
return option;
}
public static final Parcelable.Creator<Option> CREATOR = new Parcelable.Creator<Option>() {
public Option createFromParcel(Parcel in) {
return values()[in.readInt()];
}
public Option[] newArray(int size) {
return new Option[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(ordinal());
}
}
If the only reason you're making your enum Parcelable is to pass it in an Intent, you don't need to to that. enums are Serializable, so you can pass it like:
intent.putExtra("EnumValue", Option.DATA_BASE);
and retrieve it using:
Option myEnum = (Option) intent.getSerializableExtra("EnumValue");
my class looks like this when I run my application and navigate throug the different fragments sometimes it crashes and logcat says that error is BadParcelableException: Parcelable protocol requires a Parcelable.Creator object called CREATOR on class ge.mobility.weather.entity.City
here is my code
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
public class City implements Parcelable {
private String code;
private String name;
private List<CityWeather> weathers ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public List<CityWeather> getWeathers() {
if(weathers == null) {
weathers = new ArrayList<CityWeather>();
}
return weathers;
}
public void addCityWeather(CityWeather w) {
getWeathers().add(w);
}
public void addCityWeathers(List<CityWeather> w) {
getWeathers().addAll(w);
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {enter code here
// TODO Auto-generated method stub`enter code here`
}
}
You need to implement the Parcelable.Creator and also add the un/serialise methods and a constructor:
public City(Parcel in) {
readFromParcel(in);
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(code);
dest.writeString(name);
dest.writeTypedList(weathers);
}
private void readFromParcel(Parcel in) {
code = in.readString();
name = in.readString();
in.readTypedList(weathers, CityWeather.CREATOR);
}
public static final Parcelable.Creator<City> CREATOR = new Parcelable.Creator<City>() {
public City createFromParcel(Parcel in) {
return new City(in);
}
public City[] newArray(int size) {
return new City[size];
}
};
You will also need to implement the Parcelable methods for the CityWeather class.
Try this code generation library Parceler , if you are use InteliJ Use this plugin IntelliJ Plugin for Android Parcelable boilerplate code generation
I am working on an Android App, and I am trying to pass information using Parcelable. So here's what I've got.
import android.os.Parcel;
import android.os.Parcelable;
abstract class Role implements Parcelable {
private String name;
private String image;
public Role() {
}
public Role(Parcel read) {
name = read.readString();
image = read.readString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String toString() {
return this.name;
}
public static final Parcelable.Creator<Role> CREATOR =
new Parcelable.Creator<Role>() {
public Role createFromParcel(Parcel source) {
return new Role(source);
}
public Role[] newArray(int size) {
return new Role[size];
}
};
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString(name);
dest.writeString(image);
}
}
However, when I try to compile I get the Error (where I placed the comment)
Cannot instantiate the Type Role
Any thoughts on this?
Best regards
I have not used parcelable in abstract class myself, but it should be ok. You may want to check here or more generally here
I have a VERY similar class (two strings) but its a public static class.
I do new() on my string members in the constructor.
Yout class Role is defined as abstract, the abstract classes cannot be instantiated.
just define your class Role:
class Role implements Parcelable {
//...
}
As qjuanp mentioned, one cannot instantiate an abstract class (as per Java's and common OOP definition; you cannot instantiate something that is abstract, it has got to be more defined).
I'm sure you're trying to use some subclasses of Role (that's about the only way you can use both abstract and implement Parcelable here), consider using this approach:
public abstract class A implements Parcelable {
private int a;
protected A(int a) {
this.a = a;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(a);
}
protected A(Parcel in) {
a = in.readInt();
}
}
public class B extends A {
private int b;
public B(int a, int b) {
super(a);
this.b = b;
}
public static final Parcelable.Creator<B> CREATOR = new Parcelable.Creator<B>() {
public B createFromParcel(Parcel in) {
return new B(in);
}
public B[] newArray(int size) {
return new B[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(b);
}
private B(Parcel in) {
super(in);
b = in.readInt();
}
}