I am attempting to pass an array List of Custom objects through from one class to the other. I used a wrapper class to pass over the array List:
package perks;
import java.io.Serializable;
import java.util.ArrayList;
public class PerkWrapper implements Serializable {
private ArrayList<Perk> parliaments;
public PerkWrapper(ArrayList<Perk> perks) {
this.parliaments = perks;
}
public ArrayList<Perk> getParliaments() {
return this.parliaments;
}
}
I pass it like this:
i.putExtra("perks", player.perks);
Where player.perks is the arrayList containing teh Perk object
And i retrieve it like so:
PerkWrapper pw = (PerkWrapper) getIntent().getSerializableExtra("perks");
plrPerks = pw.getParliaments();
player.perks = plrPerks;
When i run the app, i get the following error:
Unable to start activity.. ClassCastException ArrayList cannot be cast to
perks.perkwrapper
Here is my Perk class: (The object in the array List):
package perks;
public class Perk implements Parcelable {
public String name;
public String desc;
public int cost;
public int roundReq;
public int rankReq;
public int minusDec;
public int plusInc;
public int autoClick;
public int rewardBonus;
public Perk() {
this.name = "";
this.desc = "";
this.cost = 0;
this.roundReq = 1;
this.rankReq = 1;
this.minusDec = 1;
this.plusInc = 1;
this.autoClick = 1;
this.rewardBonus = 1;
}
public Perk(Parcel in) {
name = in.readString();
desc = in.readString();
cost = in.readInt();
roundReq = in.readInt();
rankReq = in.readInt();
minusDec = in.readInt();
plusInc = in.readInt();
autoClick = in.readInt();
rewardBonus = in.readInt();
}
public static final Parcelable.Creator<Perk> CREATOR = new Parcelable.Creator<Perk>() {
public Perk createFromParcel(Parcel in) {
return new Perk(in);
}
public Perk[] newArray(int size) {
return new Perk[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(desc);
dest.writeInt(cost);
dest.writeInt(roundReq);
dest.writeInt(rankReq);
dest.writeInt(minusDec);
dest.writeInt(plusInc);
dest.writeInt(autoClick);
dest.writeInt(rewardBonus);
}
}
How can i prevent this error from happening or are there any alternatives to passing array Lists simply? Thank you for your time
You are passing player.perks which is an ArrayList of Perk and in your other activity you are getting PerkWrapper and hence it is giving you error.You will need to do something like this
ArrayList<Perk> perks = (ArrayList<Perk>) getIntent().getSerializableExtra("perks");
Reply to #amit singh's Answer (My reputation not yet upto comment
level)
The method specified is possible possible only for arraylist of the format ArrayList. For custom objects, this is not applicable.
To pass arraylist between activities, use-
Intent intent = new Intent(this, secondActivity.class);
intent.putStringArrayListExtra("list", samplelist);
startActivity(intent);
In your receiving intent you need to do:
Intent i = getIntent();
stock_list = i.getStringArrayListExtra("list");
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 written following code in my Activity Class,
ArrayList<TXData> data;
data= Map.getDataList();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("data",data);
Fragment fragment = new MapsFragment();
fragment.setArguments(bundle);
In MapsFragment, I have written following code to get data on onActivityCreated() Method.
ArrayList<TXData> dataList;
dataList=getArguments().getParcelableArrayList("data");
It returns following exception on Fragment class.
Caused by: java.lang.NullPointerException: Attempt to invoke virtual
method java.util.ArrayList
android.os.Bundle.getParcelableArrayList(java.lang.String) on a null
object reference
I added debug points, to find out the cause of problem, It successfully adds the data to Bundle from Activity, but its not getting any data in Fragment.
Kindly guide me what I am doing wrong here.
EDIT
Parceable Class
public class TXData implements Serializable, Parcelable{
public String id;
public String title;
public String pId = "";
public float heading;
public float pitch;
public int totalCount;
int mData;
public TXSData(){
}
protected TXData(Parcel in) {
id = in.readString();
title = in.readString();
pId = in.readString();
heading = in.readFloat();
pitch = in.readFloat();
totalCount = in.readInt();
mData = in.readInt();
minPrice = in.readInt();
maxPrice = in.readInt();
isInFilter = in.readByte() != 0;
isEnabled = in.readByte() != 0;
totalCount = in.readInt();
}
public static final Creator<TXData> CREATOR = new Creator<TXData>() {
#Override
public TXData createFromParcel(Parcel in) {
return new TXData(in);
}
#Override
public TXData[] newArray(int size) {
return new TXData[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mData);
}
The easy solution would be to drop the Parcelable and stay with Serializable.
public class TXData implements Serializable{
public String id;
public String title;
public String pId = "";
public float heading;
public float pitch;
public int totalCount;
int mData;
}
and use putExtra/getSerializableExtera instead of getParcelableArrayList/setParcelableArrayList
For big amounts of data, it is recommended to use Parcelable which is built for speed, see this post or similar...
Replace below class.
public class TXData implements Parcelable {
public String id;
public String title;
public String pId = "";
public float heading;
public float pitch;
public int totalCount;
int mData;
public TXSData(){
}
protected TXData(Parcel in) {
id = in.readString();
title = in.readString();
pId = in.readString();
heading = in.readFloat();
pitch = in.readFloat();
totalCount = in.readInt();
mData = in.readInt();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(title);
dest.writeString(pId);
dest.writeFloat(heading);
dest.writeFloat(pitch);
dest.writeInt(totalCount);
dest.writeInt(mData);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<TXData> CREATOR = new Parcelable.Creator<TXData>() {
#Override
public TXData createFromParcel(Parcel in) {
return new TXData(in);
}
#Override
public TXData[] newArray(int size) {
return new TXData[size];
}
};
}
Can you try that.
ArrayList<TXData> dataList = new ArrayList<>();
dataList.addAll(getArguments().getParcelableArrayList("data"));
Your writeToParcel method is incomplete.
Your writeToParcel should be writing all the properties in the same order as it is in the parameterized contructor: protected TXSectionData(Parcel in)
Check here: tutorial
One very important thing to pay close attention to is the order that you write and read your values to and from the Parcel. They need to match up in both cases. The mechanism that Android uses to read the Parcel is blind and completely trusts you to get the order correct, or else you will run into run-time crashes.
Try getting the Bundle object (getArguments()) in onCreate() or onCreateView()
of the fragment and not onActivityCreated().
Refer to the example from Fragment documentation.
I'm new to Android and i'm still learning. I currently have a ListView which allows you to click on an item. Clicking on an item will open a new intent displaying extra information about the item.
The thing i'm tripping up on is figuring out how to get the updated values back into my custom object and update the values in array at the correct index.
For example:
I'll add an item and set it's quantity to 2. This will appear in my ListView. Great. I decide i need 3 instead of 2, so i click the item to open the new activity, see 2 sitting in quantity, update it to 3 and hit save. On the save click i want to go back to my listview and have the updated quantity value displaying there and also updated in the array at the index.
Code for segments:
Onclick method for the listview in ItemList class
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
//#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
bean = (CustomObject) listview.getItemAtPosition(arg2);
Intent in1 = new Intent(Itemlist.this, SingleItem.class);
in1.putExtra("ActivityObject", bean);
startActivity(in1);
}
});
Adding an item the array in my ItemList class. this contain the listview.
else {
objects.add(new CustomObject(roomname.getText().toString() + " - " + resultSet.get(namecount), resultSet.get(partno), itemq, "$" + resultSet.get(rrpcol), resultSet.get(glcode), resultSet.get(desc)));
adapter.notifyDataSetChanged();
SingleItem class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_singleitem);
siname = (TextView) findViewById(R.id.siname);
sipartno = (TextView) findViewById(R.id.sipartno);
siquantity = (EditText) findViewById(R.id.siq);
sirrp = (EditText) findViewById(R.id.sirrp);
siglcode = (TextView) findViewById(R.id.siglcode);
sidesc = (EditText) findViewById(R.id.sidesc);
update = (Button) findViewById(R.id.siupdate);
Bundle b = getIntent().getExtras();
CustomObject itemInfo = b.getParcelable("ActivityObject");
siname.setText(itemInfo.getItemName());
sipartno.setText(itemInfo.getItemPartNo());
siquantity.setText(itemInfo.getItemQuantity());
sirrp.setText(itemInfo.getItemPrice());
siglcode.setText(itemInfo.getItemGLCode());
sidesc.setText(itemInfo.getItemDesc());
}
Custom Object class
public class CustomObject implements Parcelable {
private String itemName;
private String itemPartNo;
private String itemQuantity;
private String itemPrice;
private String itemGLCode;
private String itemDesc;
public CustomObject(Parcel source){
/*
* Reconstruct from the Parcel
*/
//Log.v(TAG, "ParcelData(Parcel source): time to put back parcel data");
//id = source.readInt();
itemName = source.readString();
itemPartNo = source.readString();
itemQuantity = source.readString();
itemPrice = source.readString();
itemGLCode = source.readString();
itemDesc = source.readString();
}
public CustomObject(String prop1, String prop2, String prop3, String prop4, String prop5, String prop6) {
this.itemName = prop1;
this.itemPartNo = prop2;
this.itemQuantity = prop3;
this.itemPrice = prop4;
this.itemGLCode = prop5;
this.itemDesc = prop6;
}
public String getItemName() {
return itemName;
}
public String getItemPartNo() { return itemPartNo; }
public String getItemQuantity() {
return itemQuantity;
}
public String getItemPrice() {
return itemPrice;
}
public String getItemGLCode() {return itemGLCode;}
public String getItemDesc() {return itemDesc;}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(itemName);
dest.writeString(itemPartNo);
dest.writeString(itemQuantity);
dest.writeString(itemPrice);
dest.writeString(itemGLCode);
dest.writeString(itemDesc);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public CustomObject createFromParcel(Parcel in) {
return new CustomObject(in);
}
public CustomObject[] newArray(int size) {
return new CustomObject[size];
}
};
}
I want to be able to change the quantity in the SingleItem class, click the Update button, and then have it load up the itemlist class with the updated values in the item list.
It'd be more efficient to use Fragments with your own callback interfaces defined for the activity. But, if you want to go the Activity approach, use startActivityForResult() and have your detail Activity send back a result Intent with any updates object contents.
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>() {
...
}
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?