Passing complex data directly between Fragments?What's wrong with the code? - android

i want to pass data between 2 fragments.the data i am passing is an object of a class SongDetails.Here is the Code for the fragment which is passing the data
ArrayList<SongDetails> Songinfo =new........;
if (Songinfo.size()>0)//Songinfo is an object of the class SongDetails..
{
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("Fragdata",Songinfo);
dv.setArguments(bundle);
}
code for receiving the data
Bundle bundle=this.getArguments();
final ArrayList<SongDetails> Songinfo =bundle.getParcelableArrayList("Fragdata");
when i run this it the app crashes...what am i be doing wrong??
the code for the SongDetails
package sourcecode.jazzplayer;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
public class SongDetails implements Parcelable {
Bitmap icon;
String song;
String Artist;
String Album;
String Path;
int time;
int icLauncher;
public SongDetails() {
}
public SongDetails(Parcel in) {
String[] data = new String[4];
in.readStringArray(data);
this.Path = data[0];
this.song= data[1];
this.Album= data[2];
this.Artist = data[3];
}
public String getSong() {
return song;
}
public void setSong(String song) {
this.song = song;
}
public String getArtist() {
return Artist;
}
public void setArtist(String Artist) {
this.Artist = Artist;
}
public Bitmap getIcon() {
return icon;
}
public void setIcon(Bitmap bitmap) {
this.icon = bitmap;
}
public String getPath2() {
return Path;
}
public void setPath2(String Path) {
this.Path = Path;
}
public String getAlbum() {
return Album;
}
public void setAlbum(String Album) {
this.Album = Album;
}
public void setIcon(int icLauncher) {
this.icLauncher = icLauncher;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] { this.Path,this.song,this.Album,this.Artist });
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public SongDetails createFromParcel(Parcel in) {
return new SongDetails(in);
}
public SongDetails[] newArray(int size) {
return new SongDetails[size];
}
};
}

You can't pass data directly between 2 fragments. Instead you have to pass data from your fragment 1 to your activity through an interface that you must have previously created.
Then, inside the implemented method in your activity, you should retrieve the object reference to fragment 2 and call a public method that you created and do the job.
There is a good tutorial in Android official documentation:
Android Fragments

To path any data from anywhere to anywhere else in your app use EventBus library. You can also do it by implementing observer design pattern but using library is far more easier since it also handles thread switching for you (just in case you need it)
here is the link
https://github.com/greenrobot/EventBus

Related

Unable to find generated Parcelable class

I am trying to use Parceler in my android project.
This is my Song model.
#Parcel(implementations = {SongRealmProxy.class},
value = Parcel.Serialization.BEAN,
analyze = {Song.class})
public class Song extends RealmObject {
#PrimaryKey
public String id;
public String isrc;
public String songName;
public String artistName;
public String album_id;
public String albumArtUrl;
public String genre_id;
public String genreName;
public String releaseYear;
public String price;
public String lyrics;
public String demo;
public int explicit;
}
When I try to warp these song model using bundle like this.
b.putParcelable(DATA_PARAM, Parcels.wrap(song));
I keep having this error.
org.parceler.ParcelerRuntimeException: Unable to find generated Parcelable class for com.devhousemyanmar.juketrill.models.Song, verify that your class is configured properly and that the Parcelable class com.devhousemyanmar.juketrill.models.Song$$Parcelable is generated by Parceler.
Please help me to solve this problem.
Parcelable class should be like this :
package com.yourpackagename;
public class BrushData implements Parcelable {
public static final Creator<BrushData> CREATOR = new Creator<BrushData>() {
#Override
public BrushData createFromParcel(Parcel in) {
return new BrushData(in);
}
#Override
public BrushData[] newArray(int size) {
return new BrushData[size];
}
};
private static final int VERSION = 1;
#SerializedName("icon")
private String icon;
#SerializedName("effects")
private ArrayList<String> effects;
private BrushData(Parcel parcel) {
if (parcel != null) {
readFromParcel(parcel);
}
}
#Override
public int describeContents() {
return 0;
}
private void readFromParcel(Parcel in) {
if (in.readInt() == VERSION) {
icon = in.readString();
}
}
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(VERSION);
parcel.writeString(icon);
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public ArrayList<String> getEffects() {
return effects;
}
public void setEffects(ArrayList<String> effects) {
this.effects = effects;
}
}

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.

How to parcelable object [duplicate]

This question already has answers here:
How can I make my custom objects Parcelable?
(11 answers)
Closed 6 years ago.
I am trying to learn parcelable .Earlier I was using get and set function but now I am using parcelable to pass the object to other class I made the passdata class and implemented the parcelable but how I can add the list to the class object.
class Passdata implements Parcelable {
private String title,album;
private long duration;
private Uri data,album_art;
public String getTitle() {
return title;
}
void setTitle(String title) {
this.title = title;
}
public String getAlbum() {
return album;
}
void setAlbum(String album) {
this.album = album;
}
public long getDuration() {
return duration;
}
void setDuration(long duration) {
this.duration = duration;
}
public Uri getData() {
return data;
}
void setData(Uri data) {
this.data = data;
}
public Uri getAlbum_art() {
return album_art;
}
void setAlbum_art(Uri album_art) {
this.album_art = album_art;
}
Passdata(Parcel in) {
title = in.readString();
album = in.readString();
duration = in.readLong();
data = in.readParcelable(Uri.class.getClassLoader());
album_art = in.readParcelable(Uri.class.getClassLoader());
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(title);
dest.writeString(album);
dest.writeLong(duration);
dest.writeParcelable(data, flags);
dest.writeParcelable(album_art, flags);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<Passdata> CREATOR = new Creator<Passdata>() {
#Override
public Passdata createFromParcel(Parcel in) {
return new Passdata(in);
}
#Override
public Passdata[] newArray(int size) {
return new Passdata[size];
}
};
}
how can I add the object like this
do {
int audioTitle = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
int audioartist = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST);
int audioduration = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION);
int audiodata = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
int audioalbum = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
int audioalbumid = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID);
Passdata info = new Passdata();
info.setData(Uri.parse(audioCursor.getString(audiodata)));
info.setTitle(audioCursor.getString(audioTitle));
info.setDuration(audioCursor.getLong(audioduration));
// info.setArtist(audioCursor.getString(audioartist));
info.setAlbum(audioCursor.getString(audioalbum));
info.setAlbum_art(ContentUris.withAppendedId(albumArtUri, audioCursor.getLong(audioalbumid)));
audioList.add(info);
}
I am getting error in the place were I am creating the passdata object
how to fix this??
You don't have empty constructor in PassData class. Add this code:
public Passdata() {
}

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

Android Class Parcelable with ArrayList

I have an android project where I have a class. In that class is an ArrayList<Choices>. I will be getting some XML, parsing it out, then making objects out of it which I will be passing to another activity. I'm choosing Parcelable for this.
Is Parcelable a good choice? Am I doing everything correctly? I'm not familiar really with Parcelable. My ArrayList is of another class that I made within this class. Will it properly pass that ArrayList of objects to the Parcel with it not extending Parcelable and stuff?
import java.util.ArrayList;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.os.ParcelableCompat;
public class Question implements Parcelable{
String id;
String text;
String image;
ArrayList<Choices> CHOICES;
public Question(String id, String text, String image) {
super();
this.id = id;
this.text = text;
this.image = image;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
#Override
public String toString() {
return "Question [id=" + id + ", text=" + text + ", image=" + image
+ "]";
}
// Answer Choices class
class Choices {
boolean isCorrect;
String choice;
public Choices(boolean isCorrect, String choice) {
this.isCorrect = isCorrect;
this.choice = choice;
}
public String getChoice() {
return choice;
}
public boolean getIsCorrect() {
return isCorrect;
}
#Override
public String toString() {
return "Choices [isCorrect=" + isCorrect + ", choice=" + choice
+ "]";
}
}
public static final Parcelable.Creator<Question> CREATOR = new Parcelable.Creator<Question>() {
#Override
public Question createFromParcel(Parcel in) {
return new Question(in);
}
#Override
public Question[] newArray(int size) {
return new Question[size];
}
};
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(text);
dest.writeString(image);
dest.writeList(CHOICES);
}
private Question(Parcel in) {
this.id = in.readString();
this.text = in.readString();
this.image = in.readString();
this.CHOICES = in.readArrayList(Choices.class.getClassLoader());
}
}
Thanks for any help!
If you need to pass an ArrayList between activities, then I'd go with implementing Parcelable also, as there is no other way around I guess.
However I don't think you will need that much of getters and setters. Here is your Question class which implements Parcelable:
public class Question implements Parcelable {
public String id;
public String text;
public String image;
public ArrayList<Choice> choices;
/**
* Constructs a Question from values
*/
public Question (String id, String text, String image, ArrayList<Choice> choices) {
this.id = id;
this.text = text;
this.image = image;
this.choices = choices;
}
/**
* Constructs a Question from a Parcel
* #param parcel Source Parcel
*/
public Question (Parcel parcel) {
this.id = parcel.readString();
this.text = parcel.readString();
this.image = parcel.readString();
this.choices = parcel.readArrayList(null);
}
#Override
public int describeContents() {
return 0;
}
// Required method to write to Parcel
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(text);
dest.writeString(image);
dest.writeList(choices);
}
// Method to recreate a Question from a Parcel
public static Creator<Question> CREATOR = new Creator<Question>() {
#Override
public Question createFromParcel(Parcel source) {
return new Question(source);
}
#Override
public Question[] newArray(int size) {
return new Question[size];
}
};
}
Use:
in.createTypedArrayList(Product.CREATOR)
In the constructor that takes a Parable object as a param.
In the writeToParcel method use dest.writeTypedList(product);
You have it almost, but not quite, right. The Question class looks nearly correctly Parcelable. The only thing that won't work is parcelling the array of Choices.
There are two ways that you could do it:
Make Choices Parcelable. You will have to add all the required methods, and the CREATOR. Because Android knows how to parcel ArrayLists of Parcelables, this will work.
Make parceling the Array of Choices part of parcelling the Question. To do this, you'd probably push the size of the array into the Parcel, and then loop over the Choices, pushing their values. On the other end, you'd read the count first, and then read the values for each Choice, creating each and pushing it into the new Question.
Create a new java file for "Choices" and implement "Parcelable". If you do not implement parcelable you will get run-time exception (Unable to Marshal). So use the code below :
public class Choices implements Parcelable{
boolean isCorrect;
String choice;
public Choices(boolean isCorrect, String choice) {
this.isCorrect = isCorrect;
this.choice = choice;
}
//Create getters and setters
protected Choices(Parcel in) {
isCorrect = in.readByte() != 0;
choice = in.readString();
}
public static final Creator<Choices> CREATOR = new Creator<Choices>() {
#Override
public Choices createFromParcel(Parcel in) {
return new Choices(in);
}
#Override
public Choices[] newArray(int size) {
return new Choices[size];
}
};
#Override
public String toString() {
return "Choices [isCorrect=" + isCorrect + ", choice=" + choice
+ "]";
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (isCorrect ? 1 : 0));
dest.writeString(choice);
}
}
As mentioned in above answer by #G.Blake you need to make Choices Parcelable and Android knows how to parcel ArrayLists of Parcelables

Categories

Resources