ClassCastException when trying to use ParcelableArrayList on custom object array - android

I’m trying to implement Parcelable instead of Serializable as it’s supposed to be more efficient.
From my MainActivity I want to pass the object of generic type ArrayList<LogChartData> to the same activity, so that I get it on orientation change.
If I get past this one error I’m sure I’ll run in to a lot more of them, but right now when I try to run my app I’m getting,
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at com.testapp.util.LogChartData.<init>(LogChartData.java:60)
at com.testapp.util.LogChartData.<init>(LogChartData.java:59)
at com.testapp.util.LogChartData$1.createFromParcel(LogChartData.java:51)
at com.testapp.util.LogChartData$1.createFromParcel(LogChartData.java:1)
at android.os.Parcel.readParcelable(Parcel.java:2103)
at android.os.Parcel.readValue(Parcel.java:1965)
MainActivity.java--
ArrayList<LogChartData> logss = new ArrayList<LogChartData>();
#Override
public void onSaveInstanceState(final Bundle outState) {
outState.putParcelableArrayList("logss", logss);
outState.putParcelableArrayList("alert", alert);
outState.putBoolean("isRotate", true);
super.onSaveInstanceState(outState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (savedInstanceState != null) {
try
{
logss = savedInstanceState.getParcelableArrayList("logss");
alert = savedInstanceState.getParcelableArrayList("alert");
isRotate = savedInstanceState.getBoolean("isRotate");
}
catch(ClassCastException e)
{
e.printStackTrace();
}
if(!isRotate)
someFunctionCall();
// More code here..
}
}
LogCharData.java --
public class LogChartData implements Parcelable {
public Date chartDate = null;
public ArrayList<LogEntries> logs = new ArrayList<LogEntries>();
public LogChartData(Date chartDate, ArrayList<LogEntries> logs) {
super();
this.chartDate = chartDate;
this.logs = logs;
}
public LogChartData() {
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
}
public static final Parcelable.Creator<LogChartData> CREATOR =
new Parcelable.Creator<LogChartData>() {
public LogChartData createFromParcel(Parcel in) {
return new LogChartData(in);
}
public LogChartData[] newArray(int size) {
return new LogChartData[size];
}
};
private LogChartData(Parcel in) {
this.chartDate =
(Date)in.readValue(LogChartData.class.getClassLoader()); //Error Here..
in.readList(logs, LogChartData.class.getClassLoader());
}
public Date getChartDate() {
return chartDate;
}
public void setChartDate(Date chartDate) {
this.chartDate = chartDate;
}
public ArrayList<LogEntries> getLogs() {
return logs;
}
public void setLogs(ArrayList<LogEntries> logs) {
this.logs = logs;
}
}

You cannot Directly cast the String variable directly to the Date Object like this
(Date)in.readValue(LogChartData.class.getClassLoader());
You need to use SimpleDateFormat and parse the String from Specified DateFormat and then Stored in the Date Object
Suppose if your Date as the format of "yyyy-MM-dd"
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
this.chartDate= format.parse(in.readValue(LogChartData.class.getClassLoader()));

you have to use writeToParcel(Parcel dest, int flags) method. do something like this
public LogChartData(Parcel source) {
Parcelable[] parcelables = source.readParcelableArray(Thread
.currentThread().getContextClassLoader());
for (Parcelable parcelable : parcelables) {
logs.add((LogEntries) parcelable);
}
}
#Override
public void writeToParcel(Parcel dest, int flags) {
LogEntries[] data = new LogEntries[getLogs().size()];
for (int i = 0; i < data.length; i++) {
data[i] = getLogs().get(i);
}
dest.writeParcelableArray(data, flags);
}
I don't know about Date object. it is Parcelable or not . I think you have to convert it into string using SimpleDateFormat .

LogEntries should implement Parcelable interface as well
Suppose:
public class LogEntries implements Parcelable {
private String log;
public LogEntries() {}
public LogEntries(String log) {
this.log = log;
}
public String getLog() {
return log;
}
public void setLog(String log) {
this.log = log;
}
/*--- INIT parcelable code ---*/
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
public void readFromParcel(Parcel source) {
this.log = (String)source.readValue(String.class.getClassLoader());
}
/* Parceling constructor */
public LogEntries(Parcel source) {
this();
readFromParcel(source);
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(log);
}
public static final Parcelable.Creator<LogEntries> CREATOR = new Parcelable.Creator<LogEntries>() {
#Override
public LogEntries createFromParcel(Parcel source) {
return new LogEntries(source);
}
#Override
public LogEntries[] newArray(int size) {
return new LogEntries[size];
}
};
/*--- END parcelable code ---*/
}
Then:
public class LogChartData implements Parcelable {
public Date chartDate = null;
public ArrayList<LogEntries> logs = new ArrayList<LogEntries>();
public LogChartData(Date chartDate, ArrayList<LogEntries> logs) {
super();
this.chartDate = chartDate;
this.logs = logs;
}
public LogChartData() {}
public Date getChartDate() {
return chartDate;
}
public void setChartDate(Date chartDate) {
this.chartDate = chartDate;
}
public ArrayList<LogEntries> getLogs() {
return logs;
}
public void setLogs(ArrayList<LogEntries> logs) {
this.logs = logs;
}
/*--- INIT parcelable code ---*/
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
if(chartDate!=null) {
dest.writeLong(chartDate.getTime());
}
else {
dest.writeLong(0);
}
if(logs!=null) {
dest.writeInt(logs.size()); // specify the number of logs
dest.writeTypedList(logs);
}
else {
dest.writeInt(-1); // specify there are no logs
}
}
public LogChartData(Parcel source) {
this();
readFromParcel(source);
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
public void readFromParcel(Parcel source) {
long timeMillis = source.readLong();
if(timeMillis!=0) {
this.chartDate = new Date(timeMillis);
}
else {
this.chartDate = null;
}
int logsSize = source.readInt();
if(logsSize>-1) {
this.logs = new ArrayList<LogEntries>(logsSize);
if(logsSize>0) {
source.readTypedList(logs, LogEntries.CREATOR);
}
}
else {
this.logs = null;
}
}
public static final Parcelable.Creator<LogChartData> CREATOR = new Parcelable.Creator<LogChartData>() {
#Override
public LogChartData createFromParcel(Parcel source) {
return new LogChartData(source);
}
#Override
public LogChartData[] newArray(int size) {
return new LogChartData[size];
}
};
/*--- END parcelable code ---*/
}
where you can use the long value from Date and retrieve it accordingly

Related

I can't get object from one Activity to another (android)

I want to pass my object oManagement from activity X to Y.
In X:
oManagement = new OrdersManagement();
myIntent = new Intent(this, Y.class);
Then I fill my oManagement object with separate thread.
Then I am waiting when oManagement filled and start another activity:
while (oManagement.allOrders.size() == 0) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (oManagement.allOrders.size() > 0) {
myIntent.putExtra("OrdersManagementObject", oManagement);
this.startActivity(myIntent);
}
}
And in my Y Activity:
Bundle b = this.getIntent().getExtras();
if (b != null) {
oManagement = b.getParcelable("OrdersManagementObject");
}
And now surprise -> oManagement is not null, but oManagement.allOrders.size() is 0! :( So i pass my object, but ArrayList inside by object is 0 (in moment of passing was 1 element inside that Array).
How to fix that?
EDIT:
OrdersManagement class:
public class OrdersManagement implements Parcelable {
public ArrayList<QuantorsOrder> allOrders = new ArrayList<QuantorsOrder>();
public OrdersManagement() {
}
public OrdersManagement(Parcel in) {
}
public static final Creator<OrdersManagement> CREATOR = new Creator<OrdersManagement>() {
#Override
public OrdersManagement createFromParcel(Parcel in) {
return new OrdersManagement(in);
}
#Override
public OrdersManagement[] newArray(int size) {
return new OrdersManagement[size];
}
};
public void updateListOfOrders(JSONArray jsonArray) throws JSONException {
if (jsonArray != null && jsonArray.length() > 0)
{
JSONObject json;
for (int i = 0; i < jsonArray.length(); i++)
{
json = (JSONObject)jsonArray.get(i);
if(!IsOrderAlreadyExists(json))
addOrder(json);
}
}
}
private boolean IsOrderAlreadyExists(JSONObject json) throws JSONException
{
if (allOrders.isEmpty())
return false;
else
{
for(QuantorsOrder order : allOrders)
{
if (String.valueOf(order.getId()).equals(json.get("id").toString()))
{
return true;
}
}
return false;
}
}
private void addOrder(JSONObject json) throws JSONException {
allOrders.add(new QuantorsOrder(json));
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
}
}
Your QuantorsOrdershould also implement Parcelable.
And in writeToParcel() method you should write the list and read it in constructor like this:
public void writeToParcel(Parcel out, int flags) {
out.writeTypedList(allOrders);
}
private OrdersManagement (Parcel in) {
in.readTypedList(allOrders, QuantorsOrder.CREATOR);
}
You should also implement the logic of writing and reading field in your QuantorsOrder class.
Here is example on simple class:
public class MyParcelable implements Parcelable {
private int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
public MyParcelable(Parcel in) {
mData = in.readInt();
}
}
The main thing here is happening in writeToParcel(...) method and in constructor public MyParcelable(Parcel in).

Parcable of generic array

I generate parcelable implementation with plugin and that is the code i got.
I have a an error compilation on Metrics(Parcel in).
It probably because the generic array. How can i fix it?
The generic T can can contain String, Number or boolean only.
public class Metrics<T extends Parcelable> implements Parcelable {
private T[] yData;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedArray(this.yData, flags);
}
public Metrics() {
}
protected Metrics(Parcel in) {
this.yData = in.createTypedArray(T.CREATOR);
}
public static final Parcelable.Creator<Metrics> CREATOR = new Parcelable.Creator<Metrics>() {
#Override
public Metrics createFromParcel(Parcel source) {
return new Metrics(source);
}
#Override
public Metrics[] newArray(int size) {
return new Metrics[size];
}
};
}
You can use a List instead of an array :
public class Metrics<T extends Parcelable> implements Parcelable {
private List<T> yData;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
if (yData == null || yData.size() == 0)
dest.writeInt(0);
else {
dest.writeInt(yData.size());
final Class<?> objectsType = yData.get(0).getClass();
dest.writeSerializable(objectsType);
dest.writeList(yData);
}
}
public Metrics() {
}
protected Metrics(Parcel in) {
int size = in.readInt();
if (size == 0) {
yData = null;
} else {
Class<?> type = (Class<?>) in.readSerializable();
yData = new ArrayList<>(size);
in.readList(yData, type.getClassLoader());
}
}
public static final Parcelable.Creator<Metrics> CREATOR = new Parcelable.Creator<Metrics>() {
#Override
public Metrics createFromParcel(Parcel source) {
return new Metrics(source);
}
#Override
public Metrics[] newArray(int size) {
return new Metrics[size];
}
};
}

Sending list of custom objects as an intent to another activity

I have a class Tag Model and i need to send List< TagModel> to another activity.
If i implement parcelable then I have another custom object array list in its items.
How to solve this problem?
public class TagModel {
int listing_count;
ArrayList<ListingsModel> listingsModel; //how to handle this list
String foodTypeName;
public int getListing_count() {
return listing_count;
}
public void setListing_count(int listing_count) {
this.listing_count = listing_count;
}
public String getFoodTypeName() {
return foodTypeName;
}
public void setFoodTypeName(String foodTypeName) {
this.foodTypeName = foodTypeName;
}
public ArrayList<ListingsModel> getListings() {
return listingsModel;
}
public void setListings(ArrayList<ListingsModel> listingsModel) {
this.listingsModel = listingsModel;
}
}
You 2 objects have to be Parceable to send.
I'm assuming your object "ListingsModel" is already parceable.
TagModel Parceable
public class TagModel implements Parcelable {
int listing_count;
ArrayList<ListingsModel> listingsModel; //how to handle this list
String foodTypeName;
public int getListing_count() {
return listing_count;
}
public void setListing_count(int listing_count) {
this.listing_count = listing_count;
}
public String getFoodTypeName() {
return foodTypeName;
}
public void setFoodTypeName(String foodTypeName) {
this.foodTypeName = foodTypeName;
}
public ArrayList<ListingsModel> getListings() {
return listingsModel;
}
public void setListings(ArrayList<ListingsModel> listingsModel) {
this.listingsModel = listingsModel;
}
protected TagModel(Parcel in) {
listing_count = in.readInt();
if (in.readByte() == 0x01) {
listingsModel = new ArrayList<ListingsModel>();
in.readList(listingsModel, ListingsModel.class.getClassLoader());
} else {
listingsModel = null;
}
foodTypeName = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(listing_count);
if (listingsModel == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeList(listingsModel);
}
dest.writeString(foodTypeName);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<TagModel> CREATOR = new Parcelable.Creator<TagModel>() {
#Override
public TagModel createFromParcel(Parcel in) {
return new TagModel(in);
}
#Override
public TagModel[] newArray(int size) {
return new TagModel[size];
}
};
}
For parcelable object I recommend using this great tool parcelabler

Storing ArrayList in onSavedInstanceState

I'm running an asynctask in a Fragment class and populating a ListView with the result. However I only run this asynctask the first time this fragment is instantiated.
How do I store the the ArrayList of objects created in the asynctask in onSavedInstance so I can retrieve them later?
I tried using putParcelableArrayList but I still get a NullPointerException when I try to retrieve it.
Thanks for your help
Stops:
public class Stops implements Parcelable{
private String station_name;
private ArrayList<Stops> stopTitles;
public Stops()
{
}
public Stops(Parcel source)
{
station_name = source.readString();
source.readTypedList(stopTitles, Stops.CREATOR);
}
public String getStation_name() {
return station_name;
}
public void setStation_name(String station_name) {
this.station_name = station_name;
}
public void setStopTitles(ArrayList<Stops> stopTitles) {
this.stopTitles = stopTitles;
}
public ArrayList<Stops> getStopTitles() {
return stopTitles;
}
#Override
public String toString() {
return station_name;
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int arg1) {
// TODO Auto-generated method stub
dest.writeString(station_name);
dest.writeList(stopTitles);
}
public static final Parcelable.Creator<Stops> CREATOR = new Parcelable.Creator<Stops>() {
#Override
public Stops createFromParcel(Parcel in) {
return new Stops(in);
}
#Override
public Stops[] newArray(int size) {
return new Stops[size];
}
};
}
Have you made a Parcelable implementation of the Object you are holding in the ArrayList? If the object is not parcelable you cannot pass the list to onSavedInstance example code:
public class ParcelableObject implements Parcelable {
String field;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(field);
}
public static final Parcelable.Creator<ParcelableObject> CREATOR =
new Parcelable.Creator<ParcelableObject>() {
public ParcelableObject createFromParcel(Parcel in) {
ParcelableObject obj = new ParcelableObject();
obj.readFromParcel(in)
return obj;
}
public ParcelableObject[] newArray(int size) {
return new ParcelableObject[size];
}
};
private void readFromParcel(Parcel in) {
field = in.readString()
}
}

How to implement parcelable for List<Long>

I'm trying to pass a List in my parcelable doing:
public class MetaDados implements Parcelable {
private List<Long> sizeImages;
public MetaDados(List<Long> sizeImages){
this.sizeImages = sizeImages;
}
public List<Long> getSizeImages() {
return sizeImages;
}
public void setSizeImages(List<Long> sizeImages) {
this.sizeImages = sizeImages;
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(sizeImages);
}
public static final Parcelable.Creator<MetaDados> CREATOR = new Parcelable.Creator<MetaDados>() {
#Override
public MetaDados createFromParcel(Parcel in) {
return new MetaDados(in);
}
#Override
public MetaDados[] newArray(int size) {
return new MetaDados[size];
}
};
private MetaDados(Parcel in) {
//HERE IS THE PROBLEM, I'VE tried this:
sizeImages = in.readList(sizeImages, Long.class.getClassLoader());
//but what i got: Type mismatch: cannot convert from void to List<Long>
}
}
Try this instead:
sizeImages = new ArrayList<Long>(); // or any other type of List
in.readList(sizeImages, null);
The Android documentation for Parcel.readList says:
Read into an existing List object from the parcel
and thus, you need to first create the List.

Categories

Resources