I'm trying to do a Parcelable Object to pass data between activities. With the primary variables I don't have issues, but now I need to pass an array of another object, and I don't know how to do it. I'm searching for some examples, but I didn't find a similar case to my problem.
This is my source code of the principal object:
public class Quiz implements Parcelable {
int event_id;
String name;
String business_unit;
int functional_area_business; // 0 unchecked, 1 checked
int functional_area_support; // 0 unchecked, 1 checked
Answer [] list_answers;
//GETTERS AND SETTERS
...
//
public static final Parcelable.Creator<Quiz> CREATOR = new Parcelable.Creator<Quiz>() {
public Quiz createFromParcel(Parcel in) {
return new Quiz(in);
}
public Quiz[] newArray(int size) {
return new Quiz[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(event_id);
dest.writeString(name);
dest.writeString(business_unit);
dest.writeInt(functional_area_business);
dest.writeInt(functional_area_support);
dest.writeArray(list_answers);
}
private Quiz(Parcel in) {
event_id = in.readInt();
name = in.readString();
business_unit = in.readString();
functional_area_business = in.readInt();
functional_area_support = in.readInt();
}
}
The other class is the next.
public class Answer {
int answer_id;
String value;
}
If someone could tell me what I need to modify, I will be gratefully.
Use an ArrayList instead of an Array and make Answer class Parceable then update your code to the following:
public class Quiz implements Parcelable {
int event_id;
String name;
String business_unit;
int functional_area_business; // 0 unchecked, 1 checked
int functional_area_support; // 0 unchecked, 1 checked
List<Answer > list_answers;
//GETTERS AND SETTERS
...
//
public static final Parcelable.Creator<Quiz> CREATOR = new Parcelable.Creator<Quiz>() {
public Quiz createFromParcel(Parcel in) {
return new Quiz(in);
}
public Quiz[] newArray(int size) {
return new Quiz[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(event_id);
dest.writeString(name);
dest.writeString(business_unit);
dest.writeInt(functional_area_business);
dest.writeInt(functional_area_support);
dest.writeTypedList(list_answers);
}
private Quiz(Parcel in) {
event_id = in.readInt();
name = in.readString();
business_unit = in.readString();
functional_area_business = in.readInt();
functional_area_support = in.readInt();
list_answers = new ArrayList<Answer>();
in.readTypedList(list_answers , Answer.CREATOR);
}
}
And this is the Parceable Answer:
public class Answer implements Parcelable {
int answer_id;
String value;
public static final Parcelable.Creator<Answer> CREATOR = new Parcelable.Creator<Answer>() {
public Answer createFromParcel(Parcel in) {
return new Answer(in);
}
public Answer[] newArray(int size) {
return new Answer[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(answer_id);
dest.writeString(value);
}
private Answer(Parcel in) {
answer_id = in.readInt();
value = in.readString();
}
}
Related
I have a Parcelable object that has a list of Parcelable objects. I am trying to read that list back after it has been passed from one Activity to the next, but only the first element is "un-bundled"
public class MyBundle implements Parcelable {
private List<Data> dataList;
public static final Parcelable.Creator<MyBundle> CREATOR = new Parcelable.Creator<MyBundle>() {
public MyBundle createFromParcel(Parcel in) {
return new MyBundle(in);
}
public MyBundle[] newArray(int size) {
return new MyBundle[size];
}
};
public MyBundle() {
}
public MyBundle(Parcel in) {
//dataList = new ArrayList<>();
//in.readTypedList(dataList, Data.CREATOR);
dataList = in.createTypedArrayList(Data.CREATOR);
//BOTH have the same result
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
if (dataList != null && dataList.size() > 0) {
dest.writeTypedList(dataList);
}
}
}
The data object:
/*BaseObject has the following properties:
UUID uuid;
long databaseId;
createdDate;
modifiedDate;
*/
public class Data extends BaseObject implements Parcelable {
private String name;
private String serial;
private String location;
public Data() {}
private Data(Parcel in) {
String uuidString = in.readString();
if (uuidString == null) return; //this is null!
uuid = UUID.fromString(idString);
databaseId = in.readLong();
createdDate = new Date(in.readLong());
modifiedDate = new Date(in.readLong());
location = in.readString();
name = in.readString();
serial = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(uuid.toString());
dest.writeLong(databaseId);
dest.writeLong(createdDate.getTime());
dest.writeLong(modifiedDate.getTime());
dest.writeString(name);
dest.writeString(serial);
}
public static final Parcelable.Creator<Data> CREATOR
= new Parcelable.Creator<Data>() {
public Data createFromParcel(Parcel in) {
return new Data(in);
}
public Data[] newArray(int size) {
return new Data[size];
}
};
}
What I have tried:
Debugging - I can see the first element is read fine but the rest are return null, and they do have values when they are being written
"Android, How to use readTypedList method correctly in a Parcelable class?"
"how to properly implement Parcelable with an ArrayList?"
So this is the answer: My Data parcelable misses the location element when it creates the parcel. This obviously results in some kind of offset error when READING occurs. So the coded solution is as follows:
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(uuid.toString());
dest.writeLong(databaseId);
dest.writeLong(createdDate.getTime());
dest.writeLong(modifiedDate.getTime());
dest.writeString(location); /*HERE!*/
dest.writeString(name);
dest.writeString(serial);
}
I hope this helps someone else.
I have the following models:
GitItem:
public class GitItem implements Serializable, Parcelable {
public int id;
public String name;
public String full_name;
public GitOwner owner;
public GitItem() {
}
public GitItem(Parcel in) {
id = in.readInt();
name = in.readString();
full_name = in.readString();
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags){
out.writeInt(id);
out.writeString(name);
out.writeString(full_name);
}
public static final Parcelable.Creator<GitItem> CREATOR = new Parcelable.Creator<GitItem>(){
#Override
public GitItem createFromParcel(Parcel source) {
return new GitItem(source);
}
#Override
public GitItem[] newArray(int size) {
return new GitItem[size];
}
};
}
and GitOwner:
public class GitOwner implements Serializable, Parcelable {
public String avatar_url;
public GitOwner(Parcel in) {
avatar_url = in.readString();
}
public GitOwner() {
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
}
public static final Parcelable.Creator<GitOwner> CREATOR = new Parcelable.Creator<GitOwner>(){
#Override
public GitOwner createFromParcel(Parcel source) {
return new GitOwner(source);
}
#Override
public GitOwner[] newArray(int size) {
return new GitOwner[size];
}
};
}
and then in MainActivity.java I have a List<GitItem> data; which is bound to my RecyclerView.
Basically what I am trying to achieve, is to store current state of my List<GitItem> when I change Activity or simply rotate device. Unfortunately, even though I have implemented Parcelable (as suggested by other posts), I was unable to store the instance.
Any help in this matter would be highly appreciated.
You have not implemented the complete body of Parcelable functions i.e writeToParcel in GitOwner and GitItem class
In GitOwner class
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(avatar_url);
// add this line
}
and inside GitItem use writeParcelable to write and readParcelable to read GitItem object otherwise it won't be persisted and restored
public GitItem(Parcel in) {
id = in.readInt();
name = in.readString();
full_name = in.readString();
owner = in.readParcelable(GitItem.class.getClassLoader());
// Add line to read owner object
}
public void writeToParcel(Parcel out, int flags){
out.writeInt(id);
out.writeString(name);
out.writeString(full_name);
out.writeParcelable(owner , flags);
// Add line to write owner object
}
I am including the whole structure below so you can see what I have done. But it is not working. When I send a NutHouse object across activities, the NutHouse arrives but the ArrayList is empty.
public class NutHouse implements Parcelable{
Safety safety = Safety.NICE;
String name;
String address;
ArrayList<Dog> dogs;
protected NutHouse(Parcel in) {
safety = in.readParcelable(Safety.class.getClassLoader());
name = in.readString();
address = in.readString();
dogs = in.createTypedArrayList(Dog.CREATOR);
mice = in.createTypedArrayList(Mouse.CREATOR);
}
public static final Creator<NutHouse> CREATOR = new Creator<NutHouse>() {
#Override
public NutHouse createFromParcel(Parcel in) {
return new NutHouse(in);
}
#Override
public NutHouse[] newArray(int size) {
return new NutHouse[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(safety, flags);
dest.writeString(name);
dest.writeString(address);
dest.writeTypedList(dogs);
dest.writeTypedList(mice);
}
}
class Dog implements Parcelable{
String name;
String owner;
ArrayList<Show> shows;
HashMap<String,String> friends;
protected Dog(Parcel in) {
name = in.readString();
owner = in.readString();
shows = in.createTypedArrayList(Show.CREATOR);
}
public static final Creator<Dog> CREATOR = new Creator<Dog>() {
#Override
public Dog createFromParcel(Parcel in) {
return new Dog(in);
}
#Override
public Dog[] newArray(int size) {
return new Dog[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(owner);
dest.writeTypedList(shows);
}
}
class Show implements Parcelable{
String address;
int placement;
protected Show(Parcel in) {
address = in.readString();
placement = in.readInt();
}
public static final Creator<Show> CREATOR = new Creator<Show>() {
#Override
public Show createFromParcel(Parcel in) {
return new Show(in);
}
#Override
public Show[] newArray(int size) {
return new Show[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(address);
dest.writeInt(placement);
}
}
enum Safety implements Parcelable{
NICE,PET,WILD;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeInt(ordinal());
}
public static final Parcelable.Creator<Safety> CREATOR = new Parcelable.Creator<Safety>() {
#Override
public Safety createFromParcel(final Parcel source) {
return Safety.values()[source.readInt()];
}
#Override
public Safety[] newArray(final int size) {
return new Safety[size];
}
};
}
I'm doing an app that needs to pass an object through activities, so to achieve this I've made 3 parcelable classes.
The structure is the following:
> List of Quiz:
> - int event_id;
> - String name;
> - String business_unit;
> - int functional_area_business; // 0 unchecked, 1 checked
> - int functional_area_support; // 0 unchecked, 1 checked
> - List<Quiz> list_quizs;
> |
> \
> -> Quiz:
> - int id;
> - String title;
> - String description;
> - int speaker_id;
> - String speaker_name;
> - List<Answer> list_answers;
> |
> \
> -> Answer:
> - int answer_id;
> - String title;
> - int order;
> - int type;
> - String value;
> - int quiz_parent;
As you can see, List_Quiz has some variables and a list of Quiz(class), Quiz is the same, some variables and a list of Answers(another class).
I don't know if when I send the main object "List_Quiz" through intents the data sent is the complete tree of List_Quiz with Quiz and with Answers, or only the data stored in the first parcelable class List_Quiz, because I don't get any data from answers in the activity that receives the parcelable object.
My parcelable classes are :
LIST_QUIZ
public class List_Quizs implements Parcelable {
int event_id;
String name;
String business_unit;
int functional_area_business; // 0 unchecked, 1 checked
int functional_area_support; // 0 unchecked, 1 checked
List<Quiz> list_quizs; // MyClass should implement Parcelable properly
// ==================== Parcelable ====================
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(event_id);
out.writeString(name);
out.writeString(business_unit);
out.writeInt(functional_area_business);
out.writeInt(functional_area_support);
out.writeList(list_quizs);
}
public List_Quizs() {
}
private List_Quizs(Parcel in) {
event_id = in.readInt();
name = in.readString();
business_unit = in.readString();
functional_area_business = in.readInt();
functional_area_support = in.readInt();
list_quizs = new ArrayList<Quiz>();
in.readList(list_quizs, List_Quizs.class.getClassLoader());
}
public static final Parcelable.Creator<List_Quizs> CREATOR = new Parcelable.Creator<List_Quizs>() {
public List_Quizs createFromParcel(Parcel in) {
return new List_Quizs(in);
}
public List_Quizs[] newArray(int size) {
return new List_Quizs[size];
}
};
}
QUIZ
public class Quiz implements Parcelable {
int id;
String title;
String description;
int speaker_id;
String speaker_name;
List<Answer> list_answers;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(title);
dest.writeString(description);
dest.writeInt(speaker_id);
dest.writeString(speaker_name);
dest.writeList(list_answers);
}
public Quiz(Parcel in) {
id = in.readInt();
title = in.readString();
description = in.readString();
speaker_id = in.readInt();
speaker_name = in.readString();
list_answers = new ArrayList<Answer>();
in.readList(list_answers , Quiz.class.getClassLoader());
}
public Quiz(){
}
//GETTER, SETTERS
...
//
public static final Parcelable.Creator<Quiz> CREATOR = new Parcelable.Creator<Quiz>() {
public Quiz createFromParcel(Parcel in) {
return new Quiz(in);
}
public Quiz[] newArray(int size) {
return new Quiz[size];
}
};
}
ANSWER
public class Answer implements Parcelable {
int answer_id;
String title;
int order;
int type;
String value;
int quiz_parent;
//GETTERS, SETTERS
public static final Parcelable.Creator<Answer> CREATOR = new Parcelable.Creator<Answer>() {
public Answer createFromParcel(Parcel in) {
return new Answer(in);
}
public Answer[] newArray(int size) {
return new Answer[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(answer_id);
dest.writeString(title);
dest.writeInt(order);
dest.writeInt(type);
dest.writeString(value);
dest.writeInt(quiz_parent);
}
public Answer(Parcel in) {
answer_id = in.readInt();
title = in.readString();
order = in.readInt();
type = in.readInt();
value = in.readString();
quiz_parent = in.readInt();
}
public Answer() {
}
}
You got
list_answers = new ArrayList<Answer>();
in.readList(list_answers , Quiz.class.getClassLoader());
on your Quizz class (bad copy-paste ? :p) . It should be
list_answers = new ArrayList<Answer>();
in.readList(list_answers , Answer.class.getClassLoader());
I got 3 classes. Series, Season and Episodes.
The Series class got a list of Season objects and the Season class got a list of Episode objects.
I want to send the Series object to the other activity like this.
Intent intent = new Intent(context, OtherActivity.class);
intent.putExtra("series", (Parcelable)seriesObject);
But I get a NullPointerException.
Here are the classes that implements Parcelable.
Series class:
public class Series implements Parcelable {
private int seasonCount;
public ArrayList<Season>seasons;
private String seriesName;
private int lastSeenSeason = 0;
private int lastSeenEpisode = 0;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(seasonCount);
dest.writeTypedList(seasons);
dest.writeString(seriesName);
dest.writeInt(lastSeenSeason);
dest.writeInt(lastSeenEpisode);
}
private Series(Parcel in){
seasonCount = in.readInt();
in.readTypedList(seasons, Season.CREATOR);
seriesName = in.readString();
lastSeenSeason = in.readInt();
lastSeenEpisode = in.readInt();
}
public static final Parcelable.Creator<Series> CREATOR = new Parcelable.Creator<Series>() {
public Series createFromParcel(Parcel in) {
return new Series(in);
}
public Series[] newArray(int size) {
return new Series[size];
}
};
Season class:
public class Season implements Parcelable{
private int seasonNo;
private int episodeCount;
public ArrayList<Episode> episodes;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(seasonNo);
dest.writeInt(episodeCount);
dest.writeTypedList(episodes);
}
private Season(Parcel in){
this.seasonNo = in.readInt();
episodeCount = in.readInt();
in.readTypedList(episodes, Episode.CREATOR);
}
public static final Parcelable.Creator<Season> CREATOR = new Parcelable.Creator<Season>() {
public Season createFromParcel(Parcel in) {
return new Season(in);
}
public Season[] newArray(int size) {
return new Season[size];
}
};
and the Episode class:
public class Episode implements Parcelable{
private int episodeNo;
private boolean episodeSeen;
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(episodeNo);
dest.writeByte((byte) (episodeSeen ? 1 : 0));
}
private Episode(Parcel in){
episodeNo = in.readInt();
episodeSeen = in.readByte() != 0;
}
public static final Parcelable.Creator<Episode> CREATOR = new Parcelable.Creator<Episode>() {
public Episode createFromParcel(Parcel in) {
return new Episode(in);
}
public Episode[] newArray(int size) {
return new Episode[size];
}
};
You should initialize your arrays:
public ArrayList<Episode> episodes = new ArrayList<Episode>();
public ArrayList<Season> seasons = new ArrayList<Season>();
otherwise readTypedList will fail.