Send List of Custom model between Intents - java

I've found lots of answers on SO but none working for me.
I have a List<MyModel> myList that I want to pass and retrieve through Intents.MyModel implements Parcelable and its implementation.I am using intent.putExtra("my_key",(Parcelable) myList);At runtime it throws the exception
java.util.ArrayList cannot be cast to android.os.Parcelable
And if I use putParcelableArrayListExtra then it says wrong second argument type.Any explaination or other way would be helpfulEDIT: My Model class is :
public class Filter {
private String categoryId;
public List<PrimaryFilterData> getPrimaryFilterDataList() {
return primaryFilterDataList;
}
public void setPrimaryFilterDataList(List<PrimaryFilterData> primaryFilterDataList) {
this.primaryFilterDataList = primaryFilterDataList;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public String getCategoryId() {
return categoryId;
}
public void setCategoryId(String categoryId) {
this.categoryId = categoryId;
}
private String categoryName;
private List<PrimaryFilterData> primaryFilterDataList;
public static class PrimaryFilterData implements Parcelable
{
private String filterId;
protected PrimaryFilterData(Parcel in) {
filterId = in.readString();
filterName = in.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(filterId);
dest.writeString(filterName);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<PrimaryFilterData> CREATOR = new Creator<PrimaryFilterData>() {
#Override
public PrimaryFilterData createFromParcel(Parcel in) {
return new PrimaryFilterData(in);
}
#Override
public PrimaryFilterData[] newArray(int size) {
return new PrimaryFilterData[size];
}
};
public String getFilterName() {
return filterName;
}
public void setFilterName(String filterName) {
this.filterName = filterName;
}
public String getFilterId() {
return filterId;
}
public void setFilterId(String filterId) {
this.filterId = filterId;
}
public List<SecondaryFilterData> getSecondaryFilterDataList() {
return secondaryFilterDataList;
}
public void setSecondaryFilterDataList(List<SecondaryFilterData> secondaryFilterDataList) {
this.secondaryFilterDataList = secondaryFilterDataList;
}
private String filterName;
private List<SecondaryFilterData> secondaryFilterDataList;
}
public static class SecondaryFilterData implements Parcelable {
private String secFilterName;
private String secFilterId;
private boolean isChecked=false;
public SecondaryFilterData(){}
protected SecondaryFilterData(Parcel in) {
secFilterName = in.readString();
secFilterId = in.readString();
isChecked = in.readByte() != 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(secFilterName);
dest.writeString(secFilterId);
dest.writeByte((byte) (isChecked ? 1 : 0));
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<SecondaryFilterData> CREATOR = new Creator<SecondaryFilterData>() {
#Override
public SecondaryFilterData createFromParcel(Parcel in) {
return new SecondaryFilterData(in);
}
#Override
public SecondaryFilterData[] newArray(int size) {
return new SecondaryFilterData[size];
}
};
public boolean isChecked() {
return isChecked;
}
public void setIsChecked(boolean isChecked) {
this.isChecked = isChecked;
}
public String getSecFilterName() {
return secFilterName;
}
public void setSecFilterName(String secFilterName) {
this.secFilterName = secFilterName;
}
public String getSecFilterId() {
return secFilterId;
}
public void setSecFilterId(String secFilterId) {
this.secFilterId = secFilterId;
}
}
}
Now I wish to send list of Primary data from one activity to other

You can achieve this with a Bundle.
// Important - use array list not regular list.
// MyModel must implement Parcelable
ArrayList<MyModel> myList;
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("my_key", myList);
intent.putExtras(bundle);
If your list must be of type List you can convert it at the last minute.
bundle.putParcelableArrayList("my_key", new ArrayList<MyModel>(myList));
Then in the receiving activity.
List<MyModel> myList = getIntent().getParcelableArrayListExtra("my_key");

if your MyModel class contains data memeber of only primary or String type then
Implement java.io.Serializable interface in your MyModel class.
Use Intent.putExtra(String name, Serializable value) method to send the list of model with Intent.
Intent.getSerializableExtra(String name) to retrieve list back;

You can pass your java object as a Parcelable object in the bundle. But before that you need your model java class to implement Parcelable interface and override the necessary methods.
Once you have implemented the Parcelable interface you can easily pass your model class(java class) object as Parcelable to the bundle. Small snippet below:
yourBundle.putParcelable(YOUR_OBJ_KEY,yourModelObject);
Here, yourModelObject is the object of your model class that contains all the getters and setters method that you can use.
The point i am trying to make is that you pass your entire java object to the next activity rather than the list. By doing this you will get all the information that you require in your next activity inside this java object.

I think the problem is that your List does indeed not implement Parcelable. Its content does. Try to pass an array, not a List, of Parcelables:
intent.putExtra("my_key", myList.toArray());
Edit: I just saw that it is also possible to send lists but they have to be of type ArrayList. If you don't want to convert your List to an array, try to declare your List as ArrayList<MyModel> myList where MyModel must implement Parcelable.

Phew!
After long hours of work; I come to following conculsion (I'll update answer if I find some better reason).
Parceble/Serializablwe is passing value of list as reference; that's why when I was trying to access that list from other activity; it was returning null.
Currently ; I have maintained a global list(singleton using application class) and updating / retreiving it.

Related

Firebase Realtime No properties to serialize found on class java.lang.CharSequence

I am currently using firebase recycler adapter and running into this error
"com.google.firebase.database.DatabaseException: No properties to
serialize found on class java.lang.CharSequence".
I am currently using a char sequence to retreive text from a button.
//Class for storing creating litter sightings
public class Item implements Serializable
{
//class variables
public CharSequence user;
public String brief;
//constructor
public Item(CharSequence user, String brief)
{
this.user=user;
this.brief=brief;
}
public Item()
{
}
//getters
public String getBrief() {
return brief;
}
public void setBrief(String myBrief) {
this.brief = myBrief;
}
public String getUser() {
return user;
}
}
You have to must use Percable because
Serializable
Serializable is a standard Java interface. You can just implement Serializable interface and add override methods. The problem with this approach is that reflection is used and it is a slow process. This method creates a lot of temporary objects and causes quite a bit of garbage collection. However, Serializable interface is easier to implement.
Parcelable
Parcelable process is much faster than Serializable. 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.
Look at the example below (Parcelable):
// MyObjects Parcelable class
import java.util.ArrayList;
import android.os.Parcel;
import android.os.Parcelable;
public class MyObjects implements Parcelable {
private int age;
private String name;
private ArrayList<String> address;
public MyObjects(String name, int age, ArrayList<String> address) {
this.name = name;
this.age = age;
this.address = address;
}
public MyObjects(Parcel source) {
age = source.readInt();
name = source.readString();
address = source.createStringArrayList();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
dest.writeStringList(address);
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public ArrayList<String> getAddress() {
if (!(address == null))
return address;
else
return new ArrayList<String>();
}
public static final Creator<MyObjects> CREATOR = new Creator<MyObjects>() {
#Override
public MyObjects[] newArray(int size) {
return new MyObjects[size];
}
#Override
public MyObjects createFromParcel(Parcel source) {
return new MyObjects(source);
}
};
}
// MyObjects instance
MyObjects mObjects = new MyObjects("name", "age", "Address array here");
// Passing MyOjects instance
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putExtra("UniqueKey", mObjects);
startActivity(mIntent);
Conclusion
Parcelable is faster than Serializable interface
Parcelable interface takes more time to implement compared to Serializable interface Serializable interface is easier to implement Serializable interface creates a lot of temporary objects and causes quite a bit of garbage collection
Parcelable array can be passed via Intent in android.

write parcelable on enum is crashing the app

This line is dest.writeParcelable(department, flags); causing the app to crash as I parcel the object via the intent.
When I comment the line, the app goes through but of course I don't have the department value.
public class User implements Parcelable {
public String id;
public String name;
public String email;
public Department department;
// other implementations of Parcelable
protected UserVO(Parcel in) {
id = in.readString();
name = in.readString();
email = in.readString();
department = in.readParcelable(Department.class.getClassLoader());
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(name);
dest.writeString(email);
dest.writeParcelable(department, flags); // crashes
}
}
Department Enum
public enum Department implements Parcelable {
SALES("Sales", 1),
HR("Human Resources", 2),
SHIPPING("Shipping", 3),
public final String name;
public final int ordinal;
Department(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
Department(Parcel in) {
name = in.readString();
ordinal = in.readInt();
}
public static final Creator<Department> CREATOR = new Creator<Department>() {
#Override
public Department createFromParcel(Parcel in) {
return Department.valueOf(in.readString()); // crash
//return new DeptEnum(in); // android studio generated code but has error: enum types may not be instantiated
}
#Override
public Department[] newArray(int size) {
return new Department[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(ordinal);
}
}
Error
No enum constant Department.Sales
I took the help from this answer for the line return Department.valueOf(in.readString());
Observation
I guess it has to do something with having both name and ordinal values, my enum type is not simple as in the linked answer, somehow I need to create an enum from parcel.
public Department createFromParcel(Parcel in) {
Log.d("abc", "createFromParcel: " + in.readString()); // returns null
Log.d("abc", "createFromParcel: " + in.readInt()); // returns 127 or 128
return SHIPPING; // hard coded value works but of course not a solution
}
You don't need to parcel the ordinal. Doing valueOf alone on the name would be fine
However, the parameter of valueOf must match exactly the enum defined name.
For example, this would work for sales and shipping, but not HR
Department.valueOf(in.readString().toUpperCase());
The solution you need is to loop over Department.values() and compare each name field of the values with the in.readString() result
How can I lookup a Java enum from its String value?
Or you could use the ordinal instead like so, although you're duplicating ordinal information and you'd have to guarantee that the enums have sequential numbers
return Department.values()[in.readInt() - 1]

Possible to convert ArrayList<String> to ArrayList<CustomModel>?

I'm saving some ArrayList in Sharedpreferences. But I want to set my custom model to ArrayList in adapter cause get items with getter. I really tired too many solutions from stackoverflow but I couldn't do that.
private ArrayList<String> fullList = new ArrayList<>();
to
private ArrayList<MyCustom> fullList = new ArrayList<>();
My Custom Class:
public class InstagramUserSummary implements Serializable {
public boolean is_verified;
public String profile_pic_id;
public boolean is_favorite;
public boolean is_private;
public String username;
public long pk;
public String profile_pic_url;
public boolean has_anonymous_profile_picture;
public String full_name;
#Override
public int hashCode() {
return Objects.hash(username, pk);
}
#Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (!(obj instanceof InstagramUserSummary)) {
return false;
}
InstagramUserSummary user = (InstagramUserSummary) obj;
return pk == user.getPk();
}}
List coming like this:
[InstagramUserSummary(super=dev.niekirk.com.instagram4android.requests.payload.InstagramUserSummary#a4acf205, is_verified=false, profile_pic_id=1773528799482591987_1654599017, is_favorite=false, is_private=false, username=ququletta, pk=1654599017, profile_pic_url=https://instagram.fada1-5.fna.fbcdn.net/vp/8d99014623ed527e52512a20002d884b/5C387E45/t51.2885-19/s150x150/31203725_200759604054857_5778864946146181120_n.jpg, has_anonymous_profile_picture=false, full_name=Ququletta)]
Thanks.
First of all, there is no need to have the username field be a public member of the MyCustom class. Since you're exposing access to the field via getters/setters having it public is wrong.
Aside from that, you can easily use streams and a mapping function to create a new MyCustom instance from a Stream of String.
In order to avoid boilerplate code, I would go ahead and create a static creator method in MyCustom like this:
public class MyCustom {
private String userName;
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public static MyCustom from(final String userName) {
MyCustom custom = new MyCustom();
custom.setUserName(userName);
return custom;
}
}
And then I would use this as a method reference to convert Strings over to MyCustoms thus collecting them into a new list like this:
List<String> list = new ArrayList<>();
List<MyCustom> customs = list.stream()
.map(MyCustom::from)
.collect(Collectors.toList());
Finally, also avoid initializing lists using the concrete type (e.g. ArrayList<String> someList = new ArrayList<>;'. It's much better to code the interfaces, thus doing something like List<String> someList = new ArrayList<>.
Solution:
Suppose you have a String variable in MyCustom class, like:
public class MyCustom {
private String strName;
public MyCustom(String name) {
this.strName = name;
}
public void setName(String name) {
this.strName = name;
}
public String getName() {
return this.strName;
}
}
then, you can do something like this:
for (MyCustom value : fullList) {
customFullList.add(new MyCustom(value))
}
Hope it helps.

Pass ArrayList Class Object to another fragment using Bundle in Android

I need to pass ArrayList of class object to another fragment using Bundle.
I have tried this something like this from this post.
List< SubCateogory > subCatList = allLists.getResult().getCategory().get(position).getSubCategories();
Bundle bundle = new Bundle();
bundle.putParcelableArray(ApplicationVariables.SUB_CAT_LISTS, subCatList);
It displays following error. Wrong 2nd argument type. Found: 'java.util.List<com.healthcamp.healthapp.models.HomeCategory.SubCateogory>', required: 'android.os.Parcelable[]'
My Category, SubCategory classes implements Parceable along with required methods for parceable.
Result.java
public class Results implements Parcelable {
#SerializedName("category")
#Expose
private List<Category> category = null;
public List<Category> getCategory() {
return category;
}
public void setCategory(List<Category> category) {
this.category = category;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
}
}
Category.java
public class Category implements Parcelable { ...
SubCategory.java
public class SubCateogory implements Parcelable {...
Please suggest. Thank You.
You can use a putParcelableArrayList instead of putParcelableArray
Also , you need to define your instance as an ArrayList so change it to
ArrayList< SubCateogory > subCatList

How to grab JSON Array and use gson to parse each json object? (Retrofit)

I am returning an array of results with my json Objects, and I am trying to use my customObjectResponse class to pull out each of the fields within each of the objects... the problem it is expecting an object so how do I edit my class to allow it to take in an array of object to be able to then call the fields of each object... I am confused as to what needs to be added:
Here is a response example of what is being passed to be used:
[
{
itemId: 'dfsdfsdf343434',
name: 'tests',
picture: '6976-7jv8h5.jpg',
description: 'testy.',
dateUpdated: 1395101819,
}
]
Here is my response Object Class:
public class ObjResponse{
private String itemId;
private String name;
private String picture;
private String description;
private String location;
private int dateUpdated;
private String msg;
//gridview constructor
public ObjResponse(String picture) {
this.picture = picture;
}
//public constructor
public ObjResponse() {
}
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getDateUpdated() {
return dateUpdated;
}
public void setDateUpdated(int dateUpdated) {
this.dateUpdated = dateUpdated;
}
public String getMsg() {
return msg;
}
}
what I am trying, but is not working, even if I separate the classes into their own files:
Data passed in:
items: [{obj1: "A", obj2: ["c", "d"]}, {etc...}]
public class Response {
public class List<Custom> {
private List<Custom> items;
}
public class Custom {
private String obj1;
private List<Obj2> obj2;
}
public Class Obj2 {
private String letters;
}
}
I ended up just calling in the callback a list of the customObject and it did the job...
new Callback<List<ObjResponse>>() {
I originally had trouble getting an idea of how the OP solved his problem but, after days of debugging I have finally figured out how to solve this issue.
So you essentially have data in the format like so (JSON Array of JSON Objects):
[
{
...
}
]
Your class that models the data and contains the getter and setter methods are nothing more than your typical POJO.
public class Person implements Serializable {
#SerializedName("Exact format of your json field name goes here")
private String firstName;
// Getters and Setters....
}
In your interface that contains your RESTful annotations you want to convert your call from:
Before:
public interface APInterface {
#GET("SOME URL TO YOUR JSON ARRAY")
Call<Person>(...)
}
After:
public interface APInterface {
#GET("SOME URL TO YOUR JSON ARRAY")
Call<List<Person>>(...)
}
In your android activity you want to convert all calls in the form of Call<Person> to Call<List<Person>>
Finally when making the initial asynchronous request call, you will want to convert your callbacks like so.
call.enqueue(new Callback<List<Person>>() {
#Override
public void onResponse(Call<List<Person>> call, Response<List<Person>> response) {
if(response.isSuccessful()){
List<Person> person = response.body();
// Can iterate through list and grab Getters from POJO
for(Person p: person){...}
} else {
// Error response...
}
}
#Override
public void onFailure(Call<List<Person>> call, Throwable t) {...}
});
Hope this helps others whom are lost from the accepted answer above.
This can also work by just passing an array of response objects. So if this is your response object:
public class CustomUserResponse {
public String firstName;
public String lastName;
...
}
You can use related syntax, depending on how you use the callbacks. Such as:
new Callback<CustomUserResponse[]>(){
#Override
public void success(CustomUserResponse[] customUserResponses, Response rawResponse) {
}
#Override
public void failure(RetrofitError error) {
}
};
OR
public class GetUserCommand implements Callback<CustomUserResponse[]> { ...
Put simply, in every place where you normally replace T with a response class, replace it with an array, instead as in CustomUserResponse[].
NOTE: to avoid confusing errors, be sure to also use an array in the Retrofit interface definition:
#POST ( "/users" )
public void listUsers(#Body GetUsersRequest request, Callback<CustomUserResponse[]> callback);
You could try something like this
JSONObject jsonObject = new JSONObject(<your JSON string result>);
JSONArray jsonArray = jsonObject.getJSONArray();
//use GSON to parse
if (jsonArray != null) {
Gson gson = new Gson();
ObjResponse[] objResponse = gson.fromJson(jsonArray.toString(), ObjResponse[].class);
List<ObjResponse> objResponseList = Arrays.asList(objResponse);
}
This should definitely work.

Categories