I looked everywhere and I think I'm missing something... I trying to pass my ArrayList with my object from activity to activity and getting "Unable to start activity... null pointer exception expected receiver of type EcgResultsHolder"...and the app crashes.
the type:
public class EcgDetails
{
private final String m_EcgProperties;
private final String m_Category;
public EcgDetails(String i_EcgProps, String i_Category)
{
m_EcgProperties = i_EcgProps;
m_Category = i_Category;
}
public String getEcgParams()
{
return m_EcgProperties;
}
public String getCategory()
{
return m_Category;
}
}
public class EcgResultsHolder extends ArrayList<EcgDetails> implements Parcelable
{
private static final long serialVersionUID = 663585476779879096L;
public EcgResultsHolder( )
{
}
public EcgResultsHolder(Parcel in){
readFromParcel(in);
}
#SuppressWarnings("unchecked")
public final Parcelable.Creator CREATOR = new Parcelable.Creator() {
#Override
public EcgResultsHolder createFromParcel(Parcel in) {
return new EcgResultsHolder(in);
}
#Override
public Object[] newArray(int arg0) {
return null;
}
};
private void readFromParcel(Parcel in) {
this.clear();
//First we have to read the list size
int size = in.readInt();
//Reading remember that we wrote first the Name and later the Phone Number.
//Order is fundamental
for (int i = 0; i < size; i++)
{
EcgDetails c = new EcgDetails(in.readString(), in.readString());
this.add(c);
}
}
#Override
public void writeToParcel(Parcel dest, int flags)
{
int size = this.size();
//We have to write the list size, we need him recreating the list
dest.writeInt(size);
//We decided arbitrarily to write first the Name and later the Phone Number.
for (int i = 0; i < size; i++) {
EcgDetails c = this.get(i);
dest.writeString(c.getEcgParams());
dest.writeString(c.getCategory());
}
}
#Override
public int describeContents()
{
return 0;
}
}
this is how I put it:
Bundle bundle = new Bundle();
bundle.putParcelable("EcgList", m_EcgListFromServer);
intent.putExtras(bundle);
this is how I read it on the called activity:
EcgResultsHolder m_EcgList = getIntent().getExtras().getParcelable("EcgList");
Add static qualifier to your CREATOR field. It must be static.
public static final Parcelable.Creator<EcgResultsHolder> CREATOR
= new Parcelable.Creator<EcgResultsHolder>() {
...
}
Related
I would like to send an array of objects between activities. I want to use the parcelable interface and send the data in an intent. However I keep getting errors. I have been stuck for 2 days. Here are some details about my problem.
Class A
private ProjetUI[] mProjects;
private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
Context context = view.getContext();
Intent intent = new Intent(context, ProjetListActivity.class);
intent.putExtra(ProjetListActivity.ARG_PROJECTS, mProjects);
context.startActivity(intent);
}
};
Class B
ProjetUI[] mProjects = getIntent().getParcelableArrayExtra(ARG_PROJECTS);
I get a compilation error "Incompatible types"
After casting to (ProjetUI[]), I get a runtime error "Cannot cast Parcelable[] to ProjetUI[]"
Class Projet
public class ProjetUI implements Parcelable {
private String id;
private String idParent;
private String nom;
private String description;
private List<ProjetColonneUI> colonnes;
private List<VueUI> vues;
private boolean archive;
private String version;
private String commentaire;
private boolean published;
private List<DroitAccesUI> droitAcces;
private String idDossier;
private String typeDossier;
private String idModele;
private List<ProjetDatasetUI> projetDatasets;
protected ProjetUI(Parcel in) {
id = in.readString();
idParent = in.readString();
nom = in.readString();
description = in.readString();
colonnes = in.createTypedArrayList(ProjetColonneUI.CREATOR);
vues = in.createTypedArrayList(VueUI.CREATOR);
archive = in.readInt() == 1;
version = in.readString();
commentaire = in.readString();
published = in.readInt() == 1;
droitAcces = in.createTypedArrayList(DroitAccesUI.CREATOR);
idDossier = in.readString();
typeDossier = in.readString();
idModele = in.readString();
projetDatasets = in.createTypedArrayList(ProjetDatasetUI.CREATOR);
}
public static final Creator<ProjetUI> CREATOR = new Creator<ProjetUI>() {
#Override
public ProjetUI createFromParcel(Parcel in) {
return new ProjetUI(in);
}
#Override
public ProjetUI[] newArray(int size) {
return new ProjetUI[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(getId());
parcel.writeString(getIdParent());
parcel.writeString(getNom());
parcel.writeString(getDescription());
parcel.writeTypedList(getColonnes());
parcel.writeTypedList(getVues());
parcel.writeInt(isArchive() ? 1 : 0);
parcel.writeString(getVersion());
parcel.writeString(getCommentaire());
parcel.writeInt(isPublished() ? 1 : 0);
parcel.writeTypedList(getDroitAcces());
parcel.writeString(getIdDossier());
parcel.writeString(getTypeDossier());
parcel.writeString(getIdModele());
parcel.writeTypedList(getProjetDatasets());
}
}
EDIT
This is the complete stacktrace
The other classes implement parcelable just like ProjeUI class.
Here is an example of another class that has an enum type and an example of an enum that implements parcelable
public class VueRelationUI implements Parcelable {
private String id;
private String idVue;
private String idRelation;
private RelationType typeRelation;
protected VueRelationUI(Parcel in) {
id = in.readString();
idVue = in.readString();
idRelation = in.readString();
typeRelation = in.readParcelable(RelationType.class.getClassLoader());
}
public static final Creator<VueRelationUI> CREATOR = new Creator<VueRelationUI>() {
#Override
public VueRelationUI createFromParcel(Parcel in) {
return new VueRelationUI(in);
}
#Override
public VueRelationUI[] newArray(int size) {
return new VueRelationUI[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(getId());
parcel.writeString(getIdVue());
parcel.writeString(getIdRelation());
parcel.writeParcelable(getTypeRelation(), flags);
}
}
ENUM
public enum RelationType implements Parcelable {
INNER,
OUTER;
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(ordinal());
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<RelationType> CREATOR = new Creator<RelationType>() {
#Override
public RelationType createFromParcel(Parcel parcel) {
return RelationType.values()[parcel.readInt()];
}
#Override
public RelationType[] newArray(int size) {
return new RelationType[size];
}
};
}
Any help would be much appreciated
The problem happens because of the internal implementation of Android's Parcel class. When you start the new activity, all of the intent extras are parceled and then unparceled. When this happens, the Android framework allocates a new Parcelable[], and not a new ProjetUI[]. So you get a ClassCastException when you try to cast it.
Probably the best solution would be to change your code to use ArrayList<ProjetUI> instead of ProjetUI[]. Then you can use Intent.putParcelableArrayListExtra() and getParcelableArrayListExtra() without any problems.
If you can't do that for some reason, then you will have to manually cast the array one element at a time:
Parcelable[] parcelables = getIntent().getParcelableArrayExtra(ARG_PROJECTS);
ProjetUI[] mProjects = new ProjetUI[parcelables.length];
for (int i = 0; i < parcelables.length; ++i) {
mProjects[i] = (ProjetUI) parcelables[i];
}
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 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);
I am trying to pass a FloatArrayList in parcelable from the Main Activity to the "CopyofBarGraph" activity when the user pushes a button.
Here's the code for the Bundle in the Main Activity (sent when the user pushes the button):
public void barGraphHandler (View view)
{
Bundle b = new Bundle();
b.putParcelable("fnumbers", floatarray);
Intent barintent = new Intent(this, CopyofBarGraph.class);
barintent.putExtras(b);
startActivity(barintent);
}
The code for the Parcelable ArrayList is:
public class FloatArrayList extends ArrayList<fnumber> implements Parcelable{
private static final long serialVersionUID = 663585476779879096L;
public FloatArrayList(){
}
public FloatArrayList(Parcel in){
readFromParcel(in);
}
#SuppressWarnings("rawtypes")
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public FloatArrayList createFromParcel(Parcel in) {
return new FloatArrayList(in);
}
public FloatArrayList[] newArray(int arg0) {
return new FloatArrayList[arg0];
}};
private void readFromParcel(Parcel in) {
this.clear();
int size = in.readInt();
for (int i = 0; i < size; i++) {
fnumber fn = new fnumber();
fn.setFnumber(in.readFloat());
this.add(fn);
}
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
int size = this.size();
dest.writeInt(size);
for (int i = 0; i < size; i++) {
fnumber fn = this.get(i);
dest.writeFloat(fn.getFnumber());
}}} >
For fnumber the code is:
public class fnumber {
private Float fl;
public fnumber(){
}
public fnumber(Float fl){
this.fl = fl;
}
public void setFnumber(Float fl) {
this.fl = fl;
}
public Float getFnumber() {
return fl;
} } >
Until here, everything seems to work fine.
My problem is when I try to use the FloatArrayList in the CopyofBarGrpah class:
public class CopyofBarGraph extends Activity{
public FloatArrayList floatarray;
public Intent getintent(Context context)
{
//data
Bundle b = getIntent().getExtras(); //Get the intent's extras
floatarray = b.getParcelable("fnumbers"); //get our list
float[] y = new float[floatarray.size()];
int index = 0;
for (float f : floatarray) { // THIS IS THE LINE WHERE I GET THE ERROR: TYPE MISMATCH: CANNOT CONVERT FROM ELEMENT TYPE fnumber TO float.
y[index++] = f;
}
This is my first time coding in Java and for Android and I just can't fix the problem.
Any help or hint would be very very helpful.
Thanks in advance.
It seems that you have FloatArrayList (which is ArrayList<fnumber>), i.e. is a collection of fnumbers. But you try to go with float. And Java doesn't like this
Try instead:
for (fnumber f : floatarray) {
//and use f.getFnumber() inside instead
}
Instead :
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public FloatArrayList createFromParcel(Parcel in) {
return new FloatArrayList(in);
}
public FloatArrayList[] newArray(int arg0) {
return new FloatArrayList[arg0];
}};
try to write with Type:
public static final Parcelable.Creator<FloatArrayList> CREATOR = new Parcelable.Creator<FloatArrayList>) {
#Override
public FloatArrayList createFromParcel(Parcel in) {
return new FloatArrayList(in);
}
public FloatArrayList[] newArray(int arg0) {
return new FloatArrayList[arg0];
}};
After that:
float[] y = new float[floatarray.size()];
int index = 0;
for (fnumber f : floatarray) {
y[index++] = fnumber.getFnumber();
}
I trying to pass array of objects via Parcelable. But after the transfer, the data is converted into something strange
The transmitting part:
for (int i=0; i<res.size(); i++) {
Log.d(LOG_TAG, "id = "+res.get(i).id+" weigth = "+res.get(i).weight);
}
ParcelableProducts Checked = new ParcelableProducts();
Checked.setList(res);
intent.putExtra(ParcelableProducts.class.getCanonicalName(), Checked);
The receiving part:
ParcelableProducts res = (ParcelableProducts) data.getParcelableExtra(ParcelableProducts.class.getCanonicalName());
ArrayList<prProduct> prod = res.prod;
for (int i=0; i<prod.size(); i++) {
Log.d(LOG_TAG, "id = "+prod.get(i).id+" weigth = "+prod.get(i).weight);
}
Classes
Parcelable with ArrayList:
public class ParcelableProducts implements Parcelable {
final private static String LOG_TAG = "ParcelableProducts";
public ArrayList<prProduct> prod;
public ParcelableProducts() {
prod = new ArrayList<prProduct>();
}
public void setList(ArrayList<prProduct> _prod){
prod = _prod;
}
public ArrayList<prProduct> getList() {
return prod;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeList(prod);
}
public static final Parcelable.Creator<ParcelableProducts> CREATOR = new Parcelable.Creator<ParcelableProducts>() {
public ParcelableProducts createFromParcel(Parcel in) {
return new ParcelableProducts(in);
}
public ParcelableProducts[] newArray(int size) {
return new ParcelableProducts[size];
}
};
private ParcelableProducts(Parcel parcel) {
prod = new ArrayList<prProduct>();
parcel.readTypedList(prod, prProduct.CREATOR);
}
}
and prProduct:
public class prProduct implements Parcelable {
final static String LOG_TAG = "prProduct";
public float weight;
public int id;
public prProduct(int _id, Float _weight) {
weight = _weight;
id = _id;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeFloat(weight);
parcel.writeInt(id);
}
public static final Parcelable.Creator<prProduct> CREATOR = new Parcelable.Creator<prProduct>() {
public prProduct createFromParcel(Parcel in) {
return new prProduct(in);
}
public prProduct[] newArray(int size) {
return new prProduct[size];
}
};
private prProduct(Parcel parcel) {
weight = parcel.readFloat();
id = parcel.readInt();
}
}
in log:
Transmit: id = 7 weigth = 0.0
Recive: id = 7602278 weigth = 4.2E-44
Off hand I don't see where the data is getting corrupted in transmission, but it will help to clean up your code. Personally I have fixed many weird bugs in the past when I refactor my code to improve readability. First thing you should do is remove the class "ParcelableProducts" because you don't need it. Just pass the ArrayList in the intent directly using the putParcelableArrayListExtra method. Shown here.
Also this is a bit nit picky but you shouldn't directly access your fields. It is better to set them as private and use getters/setters. Also using a for each loop for your logging statement would be a bit cleaner.
A safer PrProduct class.
//Java classes should start with capital letter
public class PrProduct implements Parcelable {
private final static String LOG_TAG = "PrProduct";
private float weight;
private int id;
public prProduct(int id, float weight) {
this.weight = weight;
this.id = id;
}
//Using getters only makes this immutable which is safer since the
//weight/id aren't likely to change.
public float getWeight(){
return weight;}
public int getId(){
return id;}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeFloat(weight);
parcel.writeInt(id);
}
public static final Parcelable.Creator<prProduct> CREATOR = new
Parcelable.Creator<prProduct>() {
public prProduct createFromParcel(Parcel in) {
return new prProduct(in);
}
public prProduct[] newArray(int size) {
return new prProduct[size];
}
};
private prProduct(Parcel parcel) {
weight = parcel.readFloat();
id = parcel.readInt();
}
}
//A sample for each loop
for(PrProduct product: prod)
Log.d(LOG_TAG, "weight=" + product.getWeight() + " id=" + product.getId());
Why do you need to create the object ParcelableProducts that implements Parcelable? I think you can just pass the arraylist directly using putParcelableArrayListExtra method from the intent?