Send List of bitmap in parcelable - android

Hello I need to send List from one activity to another, I found method in parcel
readTypedList amd write TypedList
I writethem like
parcel.writeTypedList(busImages);
and try to call like
in.readTypedList(busImages,Bitmap.Creator);
but there is error in second parametr Bitmap.Creator, Do i need create my own creator or how to solve this problem?
class code:
public class ExtendBusModel extends BusModelParcelable {
private List<Bitmap> busImages;
private String Country;
public ExtendBusModel(BusModelParcelable model, List<Bitmap> busImages, String country) {
super(model, model.getCountOfPlaces(),model.getTransportClass());
this.busImages = busImages;
Country = country;
}
protected ExtendBusModel(Parcel in) {
super(in);
Log.d("read parsel buses", TestTags.TAG1);
// in.readList(busImages,List.class.getClassLoader());
in.readTypedList(busImages,Bitmap.Creator);
Log.d("read parcel coutry",TestTags.TAG1);
Country = in.readString();
Log.d("done read",TestTags.TAG1);
// super(in);
}
#Override
public void writeToParcel(Parcel parcel, int i) {
super.writeToParcel(parcel, i);
//parcel.writeList(busImages);
parcel.writeTypedList(busImages);
parcel.writeString(Country);
}
public static final Creator<ExtendBusModel> CREATOR = new Creator<ExtendBusModel>() {
#Override
public ExtendBusModel createFromParcel(Parcel in) {
return new ExtendBusModel(in);
}
#Override
public ExtendBusModel[] newArray(int size) {
return new ExtendBusModel[size];
}
};
public List<Bitmap> getBusImages() {
if(busImages == null)
return new ArrayList<Bitmap>();
return busImages;
}
public void setBusImages(List<Bitmap> busImages) {
this.busImages = busImages;
}
public String getCountry() {
return Country;
}
public void setCountry(String country) {
Country = country;
}
}

Write your CREATOR as below...this may be solve your problem.
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public ExtendBusModel createFromParcel(Parcel in) {
return new ExtendBusModel(in);
}
public ExtendBusModel[] newArray(int size) {
new ExtendBusModel[size];
}
};

Related

Accessing and Storing multiple POJO classes in Room

I have Multiple POJO classes as type's for the main POJO class which I am using to parse the json data using Retrofit. So I provided type converters for the first level Pojo but I'm having trouble in reading the stored data because that is not in correct format.
Here is my POJO class
#Entity(tableName = "entry")
public class Entry implements Parcelable {
#NonNull
#PrimaryKey
#SerializedName("id")
private FeedID feedId;
#SerializedName("title")
private Title EntryTitle;
#SerializedName("im:image")
private List<Image> image;
#SerializedName("summary")
private Summary summary;
public Entry(){}
public FeedID getFeedId() {
return feedId;
}
public void setFeedId(FeedID feedId) {
this.feedId = feedId;
}
public Title getEntryTitle() {
return EntryTitle;
}
public void setEntryTitle(Title entryTitle) {
this.EntryTitle = entryTitle;
}
public List<Image> getImage() {
return image;
}
public void setImage(List<Image> image) {
this.image = image;
}
public Summary getSummary() {
return summary;
}
public void setSummary(Summary summary) {
this.summary = summary;
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator<Entry>() {
#Override
public Entry createFromParcel(Parcel in) {
return new Entry(in);
}
#Override
public Entry[] newArray(int size) {
return new Entry[size];
}
};
protected Entry(Parcel in) {
feedId = (FeedID) in.readValue(FeedID.class.getClassLoader());
EntryTitle = (Title) in.readValue(Title.class.getClassLoader());
if (in.readByte() == 0x01) {
image = new ArrayList<Image>();
in.readList(image, Image.class.getClassLoader());
} else {
image = null;
}
summary = (Summary) in.readValue(Summary.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(feedId);
dest.writeValue(EntryTitle);
if (image == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeList(image);
}
dest.writeValue(summary);
}
public class Title implements Parcelable {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Title> CREATOR = new Parcelable.Creator<Title>() {
#Override
public Title createFromParcel(Parcel in) {
return new Title(in);
}
#Override
public Title[] newArray(int size) {
return new Title[size];
}
};
protected Title(Parcel in) {
label = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(label);
}
}
public class Image implements Parcelable {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Image> CREATOR = new Parcelable.Creator<Image>() {
#Override
public Image createFromParcel(Parcel in) {
return new Image(in);
}
#Override
public Image[] newArray(int size) {
return new Image[size];
}
};
protected Image(Parcel in) {
label = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(label);
}
}
public class Summary implements Parcelable {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Summary> CREATOR = new Parcelable.Creator<Summary>() {
#Override
public Summary createFromParcel(Parcel in) {
return new Summary(in);
}
#Override
public Summary[] newArray(int size) {
return new Summary[size];
}
};
protected Summary(Parcel in) {
label = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(label);
}
}
public class FeedID implements Parcelable {
private Attributes attributes;
public Attributes getAttributes() {
return attributes;
}
public void setAttributes(Attributes attributes) {
this.attributes = attributes;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<FeedID> CREATOR = new Parcelable.Creator<FeedID>() {
#Override
public FeedID createFromParcel(Parcel in) {
return new FeedID(in);
}
#Override
public FeedID[] newArray(int size) {
return new FeedID[size];
}
};
protected FeedID(Parcel in) {
attributes = (Attributes) in.readValue(Attributes.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(attributes);
}
}
public class Attributes implements Parcelable {
#SerializedName("im:id")
private String id;
public String getIm() {
return id;
}
public void setIm(String im) {
this.id = im;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Attributes> CREATOR = new Parcelable.Creator<Attributes>() {
#Override
public Attributes createFromParcel(Parcel in) {
return new Attributes(in);
}
#Override
public Attributes[] newArray(int size) {
return new Attributes[size];
}
};
protected Attributes(Parcel in) {
id = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
}
}
}
and this is my TypeConverter class
public class RoomTypeConverters {
#TypeConverter
public static String toString(Entry.Title value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static Entry.Title toTitle(String value) {
Type listType = new TypeToken<Entry.Title>() {
}.getType();
return new Gson().fromJson(value, listType);
}
#TypeConverter
public static String toString(Entry.FeedID value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static Entry.FeedID toFeedID(String value) {
Type listType = new TypeToken<Entry.FeedID>() {
}.getType();
return new Gson().fromJson(value, listType);
}
#TypeConverter
public static String toString(Entry.Summary value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static Entry.Summary toSummary(String value) {
Type listType = new TypeToken<Entry.Summary>() {
}.getType();
return new Gson().fromJson(value, listType);
}
#TypeConverter
public static String toString(List<Entry.Image> value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static List<Entry.Image> toImage(String value) {
Type listType = new TypeToken<Entry.Summary>() {
}.getType();
return new Gson().fromJson(value, listType);
}
}
Do I have to create multiple POJO's like that only for one field? Do we have any other alternative?
Yes, to save a POJO you have to define a class for it (either inner or normal class).
But what I understand from your data schema is that you have a possibly complex data store server side and you want to use a subset of that data in your app. Your POJO can be simplified so you can create a Class called EntryRecord for example and define a simple setter and getter for it like this:
#Entity(tableName = "entry")
public class EntryRecord {
#NonNull
#PrimaryKey
#SerializedName("id")
private String feedId;
#SerializedName("title")
private StringEntryTitle;
#SerializedName("im:image")
private String[] image;
#SerializedName("summary")
private String summary;
public EntryRecord(Entry entry){
//Resolve primitive values from Entry class attributes..
}
public Entry getEntry(){
Entry entry = new Entry();
//Resolve entry values from primitive ones...
return entry ;
}
}
, now all you have to do is to use this class to save and restore your data, you can event make your DAO abstract to convert your POJO before save and vice versa.
P.S: if you don't have any use for such complex Schema with so many single variable classes I really advise you to define custom GSON serializer/deserializer to convert the complex POJO to simplified one from the beginning; removing such a complex schema entirely from your code base.
So after a little research I have found a annotation for which if you have multiple inner classes room will take care of it and you don't have to create any TypeConverters for it.
#Embedded Can be used as an annotation on a field of an Entity or Pojo to signal that nested fields (i.e. fields of the annotated field's class) can be referenced directly in the SQL queries.
For example, if you have 2 classes:
public class Coordinates {
double latitude;
double longitude;
}
public class Address {
String street;
#Embedded
Coordinates coordinates;
}
Room will consider latitude and longitude as if they are fields of the Address class when mapping an SQLite row to Address.
Source : Documentation

Pass ArrayList of Parcelable objects throws error

I have an object with a couple of Strings, one int and another object which has 4 inner objects. All of them implementing Parcelable. In order to generate the boilerplate code, I used Parcelable plugin from Android studio.
Even though all the objects are parcelable, I'm getting the following error: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: AlbumTrackResponse
Here's how the POJOs look like:
Main object:
public class AlbumTrackResponse implements Parcelable {
private String id;
private String albumId;
private String position;
private String title;
private int rate;
private AllServices services;
public AllServices getServices() {
return services;
}
public void setServices(AllServices services) {
this.services = services;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAlbumId() {
return albumId;
}
public void setAlbumId(String albumId) {
this.albumId = albumId;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getRate() {
return rate;
}
public void setRate(int rate) {
this.rate = rate;
}
protected AlbumTrackResponse(Parcel in) {
id = in.readString();
albumId = in.readString();
position = in.readString();
title = in.readString();
rate = in.readInt();
services = (AllServices) in.readValue(AllServices.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(albumId);
dest.writeString(position);
dest.writeString(title);
dest.writeInt(rate);
dest.writeValue(services);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<AlbumTrackResponse> CREATOR = new Parcelable.Creator<AlbumTrackResponse>() {
#Override
public AlbumTrackResponse createFromParcel(Parcel in) {
return new AlbumTrackResponse(in);
}
#Override
public AlbumTrackResponse[] newArray(int size) {
return new AlbumTrackResponse[size];
}
};
}
Inner object with 4 objects
public class AllServices implements Parcelable {
private GigRevService gigrev;
private AppleService apple;
private GoogleService google;
private SpotifyService spotify;
protected AllServices(Parcel in) {
gigrev = (GigRevService) in.readValue(GigRevService.class.getClassLoader());
apple = (AppleService) in.readValue(AppleService.class.getClassLoader());
google = (GoogleService) in.readValue(GoogleService.class.getClassLoader());
spotify = (SpotifyService) in.readValue(SpotifyService.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
public GigRevService getGigrev() {
return gigrev;
}
public void setGigrev(GigRevService gigrev) {
this.gigrev = gigrev;
}
public AppleService getApple() {
return apple;
}
public void setApple(AppleService apple) {
this.apple = apple;
}
public GoogleService getGoogle() {
return google;
}
public void setGoogle(GoogleService google) {
this.google = google;
}
public SpotifyService getSpotify() {
return spotify;
}
public void setSpotify(SpotifyService spotify) {
this.spotify = spotify;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(gigrev);
dest.writeValue(apple);
dest.writeValue(google);
dest.writeValue(spotify);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<AllServices> CREATOR = new Parcelable.Creator<AllServices>() {
#Override
public AllServices createFromParcel(Parcel in) {
return new AllServices(in);
}
#Override
public AllServices[] newArray(int size) {
return new AllServices[size];
}
};
}
The inner objects from here contain just string items.
Here's how I pass the ArrayList to the bundle:
bundle.putParcelableArrayList(MediaPlayerService.TRACK_LIST, trackList);
I'm passing the items from an Activity to a Service. Any ideas why I'm getting this error?
EDIT: Implementation of service classes
public class GoogleService implements Parcelable {
private String name;
private String uri;
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected GoogleService(Parcel in) {
name = in.readString();
uri = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(uri);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<GoogleService> CREATOR = new Parcelable.Creator<GoogleService>() {
#Override
public GoogleService createFromParcel(Parcel in) {
return new GoogleService(in);
}
#Override
public GoogleService[] newArray(int size) {
return new GoogleService[size];
}
};
}
This looks extremly strange
this.services = in.readParcelable(getClass().getClassLoader());
You are pointing out to the wrong class loader. You have to use it like this
this.services = (AllServices)in.readParcelable(AllServices.class.getClassLoader());
Besides that, I am always using this site http://www.parcelabler.com/ to quickly generate my Parceables. Or you could use it like this
services = (AllServices) in.readValue(AllServices.class.getClassLoader());
Here:
protected AllServices(Parcel in) { this.gigrev = in.readParcelable(getClass().getClassLoader());
this.apple = in.readParcelable(getClass().getClassLoader());
this.google = in.readParcelable(getClass().getClassLoader());
this.spotify = in.readParcelable(getClass().getClassLoader()); }
Replace it with
protected AllServices(Parcel in) { this.gigrev = in.readParcelable(GigRevService.class.getClassLoader());
this.apple = in.readParcelable(AppleService.class.getClassLoader());
this.google = in.readParcelable(GoogleService.class.getClassLoader());
this.spotify = in.readParcelable(SpotifyService.class.getClassLoader()); }
And replace:
this.services = in.readParcelable(getClass().getClassLoader());
With:
this.services = in.readParcelable(AllServices.class.getClassLoader());
Also can you show the GoogleService etc classes? Each inner object's class must have a Parcelable creator also and implement the Parcelable interface as well.

Android use Intent to send a list of Parcelable objects which contain a list of another Parcelable objects

In my Android app, I want to use Intent to pass a list of SingleGroup to another Activity where each SingleGroup object contains a list of SingleImage, here are class for SingleImage and SingleGroup:
public class SingleImage implements Parcelable{
public String name;
public int drawableId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDrawableId() {
return drawableId;
}
public void setDrawableId(int drawableId) {
this.drawableId = drawableId;
}
public SingleImage(String name, int drawableId)
{
this.name = name;
this.drawableId = drawableId;
}
public static final Parcelable.Creator<SingleImage> CREATOR
= new Parcelable.Creator<SingleImage>()
{
public SingleImage createFromParcel(Parcel in)
{
return new SingleImage(in);
}
public SingleImage[] newArray(int size)
{
return new SingleImage[size];
}
};
private SingleImage(Parcel in)
{
name = in.readString();
drawableId = in.readInt();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(drawableId);
}
}
Here is SingleGroup class:
public class SingleGroup implements Parcelable{
private static final String TAG = "SINGLEGROUP";
private ArrayList<SingleImage> images = new ArrayList<SingleImage>(0);
private String myTitle;
private String groupDesc;
public SingleGroup(String mTitle, String desc, ArrayList<SingleImage> imagesList) {
this.myTitle = mTitle;
this.groupDesc = desc;
this.images = imagesList;
}
public String getGroupDesc() {
return groupDesc;
}
public String getMyTitle() {
return myTitle;
}
public void setMyTitle(String myTitle) {
this.myTitle = myTitle;
}
public ArrayList<SingleImage> getImages() {
return images;
}
public void setImages(ArrayList<SingleImage> images) {
this.images = images;
}
public static final Parcelable.Creator<SingleGroup> CREATOR
= new Parcelable.Creator<SingleGroup>()
{
public SingleGroup createFromParcel(Parcel in)
{
return new SingleGroup(in);
}
public SingleGroup[] newArray(int size)
{
return new SingleGroup[size];
}
};
private SingleGroup(Parcel in)
{
myTitle = in.readString();
groupDesc = in.readString();
//problem maybe here
in.readTypedList(images,SingleImage.CREATOR);
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(myTitle);
dest.writeString(groupDesc);
//problem maybe here
dest.writeTypedList(images);
}
#Override
public String toString() {
String result = "myTitle "+myTitle+" desc "+ groupDesc + " imagesize "+images.size();
return result;
}
}
It works ok when calling to pass ArrayList<SingleImage> through Intent,
while when I called to pass ArrayLlist<SingleGroup> through Intent I got error:
Parcel android.os.Parcel#3c4c6743: Unmarshalling unknown type code
3211379 at offset 224
Any idea? Thanks in advance
---------------- Update ----------------
I have changed in.readTypedList(images, null); to in.readTypedList(images, SingleImage.CREATOR); but it still not working. same unmarshalling error
---------------- Problem Solved --------------
Thanks to Keita. The real problem is not actually listed in my code. When I passing the parcelable object, I should also include some other attributes which I missed.
Strongly recommend AS plugin Android Parcelable code generator
You must be pass SingleImage.CREATOR into method readTypedList instead of "null" value
private SingleGroup(Parcel in)
{
myTitle = in.readString();
groupDesc = in.readString();
//problem maybe here
in.readTypedList(images, SingleImage.CREATOR);
}
Try this one. That is what i always do and it work:
private SingleGroup(Parcel in)
{
myTitle = in.readString();
groupDesc = in.readString();
//problem maybe here
in.createTypedArrayList(SingleImage.CREATOR);
}
ArrayList is serialize. So try to this
public class SingleImage implements Serializable{
....
}
Refer this: ArrayList Android Documentation

Save list of objects in onSaveInstanceState

I would like to not reload RecyclerView after screen rotation. I found that I need to store/restore List from Adapter. Isn't it ?
But there is problem:
Found java.util.List<Department> requried java.util.ArrayList<?extends android.os.Parcelable>
When I try to put list in the bundle:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("key", mAdapter.getList());
}
mAdapter.getList() return the List<Department> from the Adapter of RecyclerView.
But I had implemented Parcelable inside Department model class:
#Parcel
public class Department implements UrlInterface,Parcelable {
#SerializedName("department_id")
#Expose
String departmentId;
#SerializedName("short_name")
#Expose
String shortName;
#Expose
String url;
#Expose
HashMap<Integer, Category> categories;
public Department() {}
protected Department(android.os.Parcel in) {
departmentId = in.readString();
shortName = in.readString();
url = in.readString();
}
public static final Creator<Department> CREATOR = new Creator<Department>() {
#Override
public Department createFromParcel(android.os.Parcel in) {
return new Department(in);
}
#Override
public Department[] newArray(int size) {
return new Department[size];
}
};
public String getDepartmentId() { return departmentId; }
public void setDepartmentId(String departmentId) { this.departmentId = departmentId; }
public String getShortName() { return shortName; }
public void setShortName(String shortName) { this.shortName = shortName; }
#Override
public String getUrl() { return url; }
#Override
public String getFullName() { return shortName; }
public void setUrl(String url) { this.url = url; }
public HashMap<Integer, Category> getCategories() { return categories; }
#Override
public String toString() { return shortName; }
#Override
public String getImageUrl() { return null; }
#Override
public int describeContents() { return 0; }
#Override
public void writeToParcel(android.os.Parcel dest, int flags) {
dest.writeString(departmentId);
dest.writeString(shortName);
dest.writeString(url);
}
}
What is wrong ?
ArrayList is a subclass of List, casting from List to ArrayList....bad idea...and it will create problems, especially with parcelable stuffs.
So the quick solution is to do:
outState.putParcelableArrayList("key", new ArrayList<Department>(mAdapter.getList()));.
The above solution did not work for me and continued to throw error. The below solution, provided as hind by Android Studio worked for me-
outState.putParcelableArrayList("message_list", (ArrayList<? extends Parcelable>) messageList);
Just in case someone else also tumbles upon this thread searching for similar solution!

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];
}
};
}

Categories

Resources