Reading and writing integer array to parcel - android

I could not find any solution for how to treat with integer array in case of parcel (I want to use these two functions dest.writeIntArray(storeId); and in.readIntArray(storeId);).
Here is my code
public class ResponseWholeAppData implements Parcelable {
private int storeId[];
public int[] getStoreId() {
return storeId;
}
public void setStoreId(int[] storeId) {
this.storeId = storeId;
}
#Override
public int describeContents() {
return 0;
}
public ResponseWholeAppData(){
storeId = new int[2];
storeId[0] = 5;
storeId[1] = 10;
}
public ResponseWholeAppData(Parcel in) {
if(in.readByte() == (byte)1)
in.readIntArray(storeId); //how to do this storeId=in.readIntArray(); ?
}
}
#Override
public void writeToParcel(Parcel dest, int flags) {
if(storeId!=null&&storeId.length>0)
{
dest.writeByte((byte)1);
dest.writeIntArray(storeId);
}
else
dest.writeByte((byte)0);
}
public static Parcelable.Creator<ResponseWholeAppData> getCreator() {
return CREATOR;
}
public static void setCreator(Parcelable.Creator<ResponseWholeAppData> creator) {
CREATOR = creator;
}
public static Parcelable.Creator<ResponseWholeAppData> CREATOR = new Parcelable.Creator<ResponseWholeAppData>()
{
public ResponseWholeAppData createFromParcel(Parcel in)
{
return new ResponseWholeAppData(in);
}
public ResponseWholeAppData[] newArray(int size)
{
return new ResponseWholeAppData[size];
}
};
}

When I use "in.readIntArray(storeID)", I get an error:
"Caused by: java.lang.NullPointerException
at android.os.Parcel.readIntArray(Parcel.java:672)".
Instead of using "readIntArray" I used the following:
storeID = in.createIntArray();
Now there are no errors.

I assume class MyObj implements Parcelable and implements all the required methods; I will suggest here only the details about reading / writing parcel.
If array size is known beforehand:
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeIntArray(mMyIntArray); // In this example array length is 4
}
protected MyObj(Parcel in) {
super(in);
mMyIntArray = new int[4];
in.readIntArray(mMyIntArray);
}
Otherwise:
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(mMyArray.length); // First write array length
out.writeIntArray(mMyIntArray); // Then array content
}
protected MyObj(Parcel in) {
super(in);
mMyIntArray = new int[in.readInt()];
in.readIntArray(mMyIntArray);
}

Related

Parcelable with List only deserialises first element

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.

Android Parcelable usage

I have a class with the following structure:
class Example {
Integer age;
String name;
Collection<Example2>examples;
class Example2 {
Integer number;
Collection<String>strings;
}
}
How can I make this class implement Parcelable so that I can send its object across activities.
The simplest way will be to use #AutoParcel and let it handle the heavy lifting for you.
You should take a look at this thread : Android: Making a class parcelable
So your classes should be something like :
class Example implements Parcelable {
Integer age;
String name;
ArrayList<Example2> examples;
public Example(Parcel in) {
examples = new ArrayList<>();
readFromParcel(in);
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
dest.writeList(examples != null ? examples : new ArrayList());
}
private void readFromParcel(Parcel in) {
age = in.readInt();
name = in.readString();
in.readList(examples, Example2.class.getClassLoader());
}
public static final Creator<Example> CREATOR = new Creator<Example>() {
#Override
public Example createFromParcel(Parcel in) {
return new Example(in);
}
#Override
public Example[] newArray(int size) {
return new Example[size];
}
};
}
and
class Example2 implements Parcelable {
Integer number;
ArrayList<String> labels;
public Example2(Parcel in) {
labels = new ArrayList<>();
readFromParcel(in);
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInteger(number);
dest.writeList(labels != null ? labels : new ArrayList());
}
#Override
public int describeContents() {
return 0;
}
private void readFromParcel(Parcel in) {
number = in.readInteger();
in.readStringList(labels);
}
public static final Creator<Example2> CREATOR = new Creator<Example2>() {
#Override
public Example2 createFromParcel(Parcel in) {
return new Example2(in);
}
#Override
public Example2[] newArray(int size) {
return new Example2[size];
}
};
}

Sending Nested Parcelable with Intent

I am trying to send a Parcelable object which also contains another Parcelable object with Intent. However, I am getting NullPointer Exception. Could you please tell me where I am doing wrong?
A.java
public class A implements Parcelable {
private ArrayList<B> var;
public A()
{
this.var = new ArrayList<B>();
}
public void addToB(B b)
{
var.add(b);
}
public ArrayList<B> getB() {
return var;
}
public void setB(ArrayList<B> b) {
this.var = b;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(this.var);
}
private A (Parcel in){
in.readTypedList(this.var, B.CREATOR);
}
public static final Parcelable.Creator<A> CREATOR = new Parcelable.Creator<A>() {
public A createFromParcel(Parcel in) {
return new A(in);
}
public A[] newArray(int size) {
return new A[size];
}
};
}
B.java
public class B implements Parcelable {
private String type;
public B(String type)
{
this.type=type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel arg0, int arg1) {
arg0.writeString(this.type);
}
private B(Parcel in) {
this.type=in.readString();
}
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];
}
};
}
I send the A object with Intent like this:
Intent i = new Intent(Bla.this, Blabla.class);
i.putExtra("info", objectA);
startActivity(i);
I receive the parcelable like this:
Intent i = getIntent();
ObjectA ci = (ObjectA)i.getParcelableExtra("info");
You have to instanciate your ArrayList< B > in :
private A (Parcel in){
var = new ArrayList<B>();
in.readTypedList(this.var, B.CREATOR);
}
Say if it works :)
You are not assigning data to var variable in constructor.
change it like
private A (Parcel in){
var=(ArrayList)in.readTypedList(this.var, B.CREATOR);
}
Edit::
Change your code like this and try
#Override
public void writeToParcel(Parcel dest, int flags) {
B[] data = new B[var.size()];
for (int i = 0; i < data.length; i++) {
data[i] = var.get(i);
}
dest.writeParcelableArray(data, flags);
}
public A(Parcel in) {
Parcelable[] parcelables = in.readParcelableArray(Thread
.currentThread().getContextClassLoader());
ArrayList<B> list = new ArrayList<B>();
for (Parcelable parcelable : parcelables) {
list.add((B) parcelable);
}
var = list;
}
you have problem with parsing the arraylist... do these changes..
private A (Parcel in){
in.readTypedList(this.var, B.CREATOR);
}
to
this.var=in.readArrayList(B.class.getClassLoader());
and
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(this.var);
}
to
dest.writeList(this.var);

How to extend android class which implements Parcelable interface?

First of all i have check this answer.
What i am trying to do is extending Location class calling it LocationPlus which has some
member variables. functionality i am trying to achieve is pass the object of LocationPlus class from one activity to another.
Here is my CREATOR
public static final Parcelable.Creator<LocationPlus> CREATOR = new Parcelable.Creator<LocationPlus>() {
#Override
public LocationPlus createFromParcel(Parcel source) {
return new LocationPlus(source);
}
#Override
public LocationPlus[] newArray(int size) {
return new LocationPlus[size];
}
};
problem i am facing is this error
Implicit super constructor Location() is undefined. Must explicitly invoke another constructor
when trying to write constructor
public LocationPlus(Parcel in) {
Someone in comment ask me to post LocationPlus class so here it is
public class LocationPlus extends Location{
private int mBattery = -1;
public LocationPlus(String locationName) {
super(locationName);
}
public LocationPlus(Location location) {
super(location);
}
public int getmBattery() {
return mBattery;
}
public void setmBattery(int mBattery) {
this.mBattery = mBattery;
}
#Override
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<LocationPlus> CREATOR = new Parcelable.Creator<LocationPlus>() {
#Override
public LocationPlus createFromParcel(Parcel source) {
return new LocationPlus(source);
}
#Override
public LocationPlus[] newArray(int size) {
return new LocationPlus[size];
}
};
#Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(mBattery);
}
public LocationPlus(Parcel in) {
mBattery =in.readInt();
}
}
Parcelable, the Speed King
According to google engineers, this code will run significantly faster. One of the reasons for this is that we are being explicit about the serialization process instead of using reflection to infer it. It also stands to reason that the code has been heavily optimized for this purpose.
public abstract class BaseClass implements Parcelable {
public String FullName;
public boolean IsValidUser;
public String UserName;
public BaseClass () {
}
protected BaseClass(Parcel in) {
FullName = in.readString();
IsValidUser = in.readByte() != 0;
UserName = in.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(FullName);
dest.writeByte((byte) (IsValidUser ? 1 : 0));
dest.writeString(UserName);
}
}
Child class will be as follows with usage of list adding into parcelable object:
public class DerivedClass extends BaseClass {
public boolean IsSuccess;
public String Message;
public List<AnotherClass> AnotherClassObj;
public DerivedClass () {
super();
}
protected DerivedClass(Parcel in) {
super(in);
AnotherClassObj = new ArrayList<AnotherClass>();
IsSuccess = in.readByte() != 0;
Message = in.readString();
AnotherClassObj = in.readArrayList(AnotherClass.class.getClassLoader());
}
public static final Creator<DerivedClass> CREATOR = new Creator<DerivedClass>() {
#Override
public DerivedClass createFromParcel(Parcel in) {
return new DerivedClass(in);
}
#Override
public DerivedClass[] newArray(int size) {
return new DerivedClass[size];
}
};
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeByte((byte) (IsSuccess ? 1 : 0));
dest.writeString(Message);
dest.writeList(AnotherClassObj);
}
public int describeContents() {
return 0;
}
}
Another child class :
public class AnotherClass extends BaseClass {
public AnotherClass() {
super();
}
protected AnotherClass(Parcel in) {
super(in);
}
public int describeContents() {
return 0;
}
public static final Creator<AnotherClass> CREATOR = new Creator<AnotherClass>() {
#Override
public AnotherClass createFromParcel(Parcel in) {
return new AnotherClass(in);
}
#Override
public AnotherClass[] newArray(int size) {
return new AnotherClass[size];
}
};
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
}
}
In Activity:
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.putExtra("UserObject", parcelableObject);
startActivity(intent);
finish();
In receiving activity:
Bundle extras = getIntent().getExtras();
if (extras != null) {
userObject = extras.getParcelable("UserObject");
}
Hi I've do research a lot about this, but I couldn't find useful anything. I try solution below and it worked for me.
Let say your super class has only int variable named "mData".
public class Location implements Parcelable {
protected int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<Location> CREATOR
= new Parcelable.Creator<Location>() {
public Location createFromParcel(Parcel in) {
return new Location(in);
}
public Location[] newArray(int size) {
return new Location[size];
}
};
private Location(Parcel in) {
mData = in.readInt();
}
}
Then, your extended class has only int variable named "mBattery".
public class LocationPlus extends Location {
protected int mBattery;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mBattery);
}
public static final Parcelable.Creator<LocationPlus> CREATOR
= new Parcelable.Creator<LocationPlus>() {
public LocationPlus createFromParcel(Parcel in) {
return new LocationPlus(in);
}
public LocationPlus[] newArray(int size) {
return new LocationPlus[size];
}
};
private LocationPlus(Parcel in) {
mBattery = in.readInt();
}
}
So far, LocationPlus works fine. But we don't set variable of super class. Firstly, I set super class' variables on extended class with super(..) method. But it didn't work.
private LocationPlus(Parcel in) {
super(in);
mBattery = in.readInt();
}
Instead of code above, you should set all super class' variables explicitly. Super class' variables should be protected. Final constructor should be like this:
private LocationPlus(Parcel in) {
mData = in.readIn();
mBattery = in.readInt();
}
and writeToParcel method should be like this:
public void writeToParcel(Parcel out, int flags) {
out.writeIn(mData);
out.writeInt(mBattery);
}
Try this solution:
public static final Parcelable.Creator<LocationPlus> CREATOR =
new Parcelable.Creator<LocationPlus>() {
#Override
public LocationPlus createFromParcel(Parcel in) {
Location l = Location.CREATOR.createFromParcel(in);
LocationPlus lp = new LocationPlus(l);
lp.mBattery= in.readInt();
return lp;
}
#Override
public LocationPlus[] newArray(int size) {
return new LocationPlus[size];
}
};
#Override
public void writeToParcel(Parcel parcel, int flags) {
super.writeToParcel(parcel, flags);
parcel.writeInt(mBattery);
}
According to the Android docs, there isn't a Location() constructor for the Location class. When initializing your LocationPlus class, you need to call either super(String provider) or super(Location l).
Edit: Corrected syntax
(See Location Android Doc)

Android Parcelable Problem with array

Hi everybody i have build a class that implements Parcelable but one of the arraylist attributes i have define gets empty when i read the class. Here is the code
package roblestech.laCartelera;
import java.util.ArrayList;
import android.os.Parcel;
import android.os.Parcelable;
public class ProgramacionPelicula implements Parcelable {
public ProgramacionPelicula() {
}
public ProgramacionPelicula(Pelicula pelicula) {
_pelicula = pelicula;
}
public ProgramacionPelicula(Cine cine) {
_cine = cine;
}
public String toString() {
if (getVista() == ProgramacionPelicula.VISTA_PELICULA) {
return getCine().getCine();
} else {
return getPelicula().getTituloOriginal();
}
}
private int _idProgramacion;
public void setIdProgramacion(int value) {
_idProgramacion = value;
}
public int getIdProgramacion() {
return _idProgramacion;
}
private Pelicula _pelicula;
// public ArrayList<Pelicula> _peliculas = new ArrayList<Pelicula>();
public void setPelicula(Pelicula pelicula) {
_pelicula = pelicula;
}
public Pelicula getPelicula() {
return _pelicula;
}
private Cine _cine;
public void setCine(Cine cine) {
_cine = cine;
}
public Cine getCine() {
return _cine;
}
public ArrayList<Tanda> _tandas = new ArrayList<Tanda>();
public void setTandas(ArrayList<Tanda> value) {
_tandas = value;
}
public void setTandas(Object[] tandas) {
for (Object tanda : tandas) {
if (tanda instanceof Tanda) {
_tandas.add((Tanda) tanda);
}
}
}
public void addTanda(Tanda value) {
_tandas.add(value);
}
public ArrayList<Tanda> getTandas() {
return _tandas;
}
private String _sala = "";
public void setSala(String value) {
_sala = value;
}
public String getSala() {
return _sala;
}
public static final int VISTA_CINE = 0;
public static final int VISTA_PELICULA = 1;
private int _vista = VISTA_CINE;
public int getVista() {
return _vista;
}
public ProgramacionPelicula toPelicula() {
ProgramacionPelicula programacionPelicula = new ProgramacionPelicula();
programacionPelicula._idProgramacion = _idProgramacion;
programacionPelicula._pelicula = _pelicula;
programacionPelicula._cine = _cine;
programacionPelicula._tandas = _tandas;
programacionPelicula._sala = _sala;
programacionPelicula._vista = VISTA_PELICULA;
return programacionPelicula;
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(getIdProgramacion());
dest.writeString(getSala());
ArrayList<Pelicula> peliculas = new ArrayList<Pelicula>();
peliculas.add(getPelicula());
Object[] objectsPeliculas = peliculas.toArray();
dest.writeArray(objectsPeliculas);
Object[] objectsTanda = getTandas().toArray();
dest.writeArray(objectsTanda);
}
// this is used to regenerate your object. All Parcelables must have a
// CREATOR that implements these two methods
public static final Parcelable.Creator<ProgramacionPelicula> CREATOR = new Parcelable.Creator<ProgramacionPelicula>() {
public ProgramacionPelicula createFromParcel(Parcel in) {
return new ProgramacionPelicula(in);
}
public ProgramacionPelicula[] newArray(int size) {
return new ProgramacionPelicula[size];
}
};
// example constructor that takes a Parcel and gives you an object populated
// with it's values
private ProgramacionPelicula(Parcel in) {
this();
setIdProgramacion(in.readInt());
setSala(in.readString());
Object[] obj = in.readArray(Pelicula.class.getClassLoader());
setPelicula((Pelicula) obj[0]);
setTandas(in.readArray(Tanda.class.getClassLoader()));
}
}
Thanks in advance everybody.
Another way to pass an array would be using typed arrays as follows:
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mMyArray.length);
dest.writeTypedArray(mMyArray, flags);
}
And to read it back like this:
public MyParcelableObject(Parcel in) {
mMyArray = new MyOtherParcelableObject[in.readInt()];
in.readTypedArray(mMyArray, MyOtherParcelableObject.CREATOR);
}
In short, write the length of the array as an int value to the parcelable, right before writing its values, so you can create an array of the same size before reading it.
In order to read/write a custom class property you need to use writeParcelable and readParcelable in stead of writing it into an array.
Change your parcel constructor to:
private ProgramacionPelicula(Parcel in) {
this();
setIdProgramacion(in.readInt());
setSala(in.readString());
_pelicula = in.readParcelable(Pelicula.class.getClassLoader());
setTandas(in.readArray(Tanda.class.getClassLoader()));
}
And your writeToParcel method to:
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(getIdProgramacion());
dest.writeString(getSala());
dest.writeParcelable(_pelicula, flags);
Object[] objectsPeliculas = peliculas.toArray();
dest.writeArray(objectsPeliculas);
Object[] objectsTanda = getTandas().toArray();
dest.writeArray(objectsTanda);
}
If you really want to use an array, you must invoke the readTypedArray/writeTypedArray methods. Like so:
#Override
public void writeToParcel(Parcel dest, int flags) {
ArrayList<Pelicula> list = new ArrayList<Pelicula>();
list.add(_pelicula);
dest.writeTypedList(list);
}
private ProgrammacionPelicula(Parcel in) {
ArrayList<Pelicula> list = new ArrayList<Pelicula>();
in.readTypedList(list, ProgrammacionPelicula.CREATOR);
}
And you should do the same for your Tanda properties.
Hope this helps.
The most concise, write like this:
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedArray(this.mMyArray, flags);
}
and read like this:
public MyParcelableObject(Parcel in) {
this.mMyArray = in.createTypedArray(MyOtherParcelableObject.CREATOR);
}

Categories

Resources