I am trying to pass array of objects from one activity to another activity using parcelable. Here i faced this problem Class not found when unmarshalling:
First Activity code
intent.setExtrasClassLoader(MenueItemDetails.class.getClassLoader());
intent.putExtra("menue",myArray);
Second Activity code
myArray = (MenueItemDetails[])getIntent().getParcelableArrayExtra("menue");
it's my class which is parceable
public class MenueItemDetails implements Parcelable {
private int id = 0, menueId = 0, type = 0, typeId = 0, styleId = 0, lineBefore = 0;
private String webSite = "", title = "", icon = "";
#Override
public int describeContents() {
return 0;
}
// write your object's data to the passed-in Parcel
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(id);
out.writeInt(menueId);
out.writeInt(type);
out.writeInt(typeId);
out.writeInt(styleId);
out.writeInt(lineBefore);
out.writeString(webSite);
out.writeString(title);
out.writeString(icon);
}
private MenueItemDetails(Parcel in) {
id = in.readInt();
menueId = in.readInt();
type = in.readInt();
typeId = in.readInt();
styleId= in.readInt();
lineBefore= in.readInt();
webSite=in.readString();
title= in.readString();
icon=in.readString();
}
public MenueItemDetails() {
id = 0;
menueId = 0;
type = 0;
styleId= 0;
lineBefore= 0;
webSite="";
title= "";
icon="";
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public MenueItemDetails createFromParcel(Parcel in) {
return new MenueItemDetails(in);
}
public MenueItemDetails[] newArray(int size) {
return new MenueItemDetails[size];
}
};
public int getLineBefore() {
return lineBefore;
}
public void setLineBefore(int lineBefore) {
this.lineBefore = lineBefore;
}
public void setId(int id) {
this.id = id;
}
public void setMenueId(int menueId) {
this.menueId = menueId;
}
public void setTitle(String title) {
this.title = title;
}
public void setIcon(String icon) {
this.icon = icon;
}
public void setType(int type) {
this.type = type;
}
public void setTypeId(int typeId) {
this.typeId = typeId;
}
public void setStyleId(int styleId) {
this.styleId = styleId;
}
public int getId() {
return id;
}
public String getWebSite() {
return webSite;
}
public void setWebSite(String webSite) {
this.webSite = webSite;
}
public int getMenueId() {
return menueId;
}
public String getTitle() {
return title;
}
public String getIcon() {
return icon;
}
public int getType() {
return type;
}
public int getTypeId() {
return typeId;
}
public int getStyleId() {
return styleId;
}
}
Your Second Activity must be like this:
Intent intent = getIntent();
intent.setExtrasClassLoader(MenueItemDetails.class.getClassLoader());
myArray = (MenueItemDetails[]) intent.getParcelableArrayExtra("menue");
Your code to pass the arraylist in first activity code is not correct.Send the arraylist in your activities as below:
First Activity Code
intent.setExtrasClassLoader(MenueItemDetails.class.getClassLoader());
intent.putParcelableArrayListExtra("menue",myArray);
And receive the arraylist as below in Second activity.
Second Activity Code
ArrayList<MenueItemDetails> myarray=getIntent().getParcelableArrayListExtra("menue");
The problem with your code is that it is used to send and receive single Object,not the arraylist.If you still have problems in using Parceable object,make sure to use Android Parceable Code generator plugin for Android Studio.
If your task is Pass data from activity to activity or Fragment
Than instead of Using Parcelable you can use Serializable object and pass it to intent it take very less time to implement and code than Parcelable
https://stackoverflow.com/a/39631604/4741746
implement serializable in your class
public class Place implements Serializable{
private int id;
private String name;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then you can pass this object in intent
Intent intent = new Intent(this, SecondAct.class);
intent.putExtra("PLACE", Place);
startActivity();
int the second activity you can get data like this
Place place= (Place) getIntent().getSerializableExtra("PLACE");
Related
I'm trying to pass a Parcelable class from one Activity to another. I do it like this:
Intent intent = new Intent(ClosedChatActivity.this, AdminProfileActivity.class);intent.putExtra("adminProfile", adminProfile);
startActivity(intent);
And then get it in the other Activity like this:
adminProfile = (AdminProfile) getIntent().getExtras().getParcelable("adminProfile");
This is the AdminProfile class and the WebLink class it has inside:
public class AdminProfile implements Parcelable {
public static final Creator<AdminProfile> CREATOR = new Creator<AdminProfile>() {
#Override
public AdminProfile createFromParcel(Parcel in) {
return new AdminProfile(in);
}
#Override
public AdminProfile[] newArray(int size) {
return new AdminProfile[size];
}
};
public Long idUser;
public String name;
public String professio;
public String description;
public List<WebLink> webLinks;
public Long idOficina;
protected AdminProfile(Parcel in) {
idUser = in.readLong();
name = in.readString();
professio = in.readString();
description = in.readString();
webLinks = in.createTypedArrayList(WebLink.CREATOR);
idOficina = in.readLong();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeLong(idUser);
parcel.writeString(name);
parcel.writeString(professio);
parcel.writeString(description);
parcel.writeLong(idOficina);
parcel.writeTypedList(webLinks);
}
}
public class WebLink implements Parcelable {
public static final Creator<WebLink> CREATOR = new Creator<WebLink>() {
#Override
public WebLink createFromParcel(Parcel in) {
return new WebLink(in);
}
#Override
public WebLink[] newArray(int size) {
return new WebLink[size];
}
};
public String name;
public String url;
protected WebLink(Parcel in) {
name = in.readString();
url = in.readString();
}
#Override
public boolean equals(#Nullable Object obj) {
WebLink webLink = (WebLink) obj;
assert webLink != null;
return this.name.equals(webLink.name) && this.url.equals(webLink.url);
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeString(url);
}
}
When I get the object, the two Strings in it aren't the same I sent. Why is that?
The weird thing is that I have another Parcelable class which contains an AdminProfile, and when sending that class it does send fine with the Weblinks included, but if I send only an AdminProfile somewhere in the way it fails.
When you read and write Parcelable classes, you need to make sure that the order of the elements is exactly the same.
You are writing idOficina followed by WebLinks, but you are reading them in the opposite order.
I want to pass MyObj[ ] between activities.
I'm using an Intent and Parcelable to do so, but when I try to receive that data in Activity B I get the error:
"java.lang.ClassCastException: android.os.Parcelable[] cannot be cast to com.hfad.myapp.MyObj[ ]".
I saw that many people had problems with this but couldn't find a solution to my case.
This answer doesn't solve it android.os.Parcelable[] cannot be cast to... Error
MyObj class
#Entity (tableName = "myobj")
public class MyObj implements Parcelable {
#PrimaryKey(autoGenerate = true)
private int id;
private String productName;
private int numberOfproducts;
protected MyObj (Parcel in) {
id = in.readInt();
productName = in.readString();
numberOfproducts = in.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(productName);
dest.writeInt(numberOfproducts);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<MyObj> CREATOR = new Creator<MyObj>() {
#Override
public MyObj createFromParcel(Parcel in) {
return new MyObj(in);
}
#Override
public MyObj[] newArray(int size) {
return new MyObj[size];
}
};
public int getId() {
return id;
}
public String getProductName() {
return productName;
}
public int getNumberOfproducts() {
return numberOfproducts;
}
public void setId(int id) {
this.id = id;
}
public MyObj(String productName, int numberOfproducts) {
this.productName = productName;
this.numberOfproducts = numberOfproducts;
}
}
Activity A
Intent intent = new Intent(getContext(), ActivityB.class);
intent.putExtra("array", array);
startActivity(intent);
Activity B
//Here the error occurs
MyObj[] myArray = (MyObj[]) getIntent().getParcelableArrayExtra("array");
Is there a way to fix this?
Or should I use a different approach to pass data between Activities?
The String variable finalMapSearchUrl gets concatenated with another String (mapUrlParam) in the constructor and the Log shows the expected value : Final map URL : https://www.google.com/maps/search/?api=1&query=Spilia%20Beach (here the mapUrlParam = Spilia Beach). However, when i call the getMapSearchUrl() method from outside the class and monitor the Log, the finalMapSearchUrl's value is now back to the default https://www.google.com/maps/search/?api=1&query=. Log in getMapSearchUrl() : finalMapSearchUrl = https://www.google.com/maps/search/?api=1&query=. Any ideas on when,why and how it's value is not preserved outside of the constructor?
PlaceObject.java class:
public class PlaceObject implements Parcelable { // Implementing the Parcelable interface to allow for cleaner and faster code
private static final String TAG = PlaceObject.class.getSimpleName();
private static final String baseMapSearchUrl = "https://www.google.com/maps/search/?api=1&query="; // Base url for launching a Map activity with a Search Intent
// Using int so that the values can be accessed via R.string etc.
private int name;
private int description;
private int category;
private String locationDistance;
private String finalMapSearchUrl = baseMapSearchUrl;
PlaceObject(int name, int description, int category , String locationDistance, String mapUrlParam) {
this.name = name;
this.description = description;
this.locationDistance = locationDistance;
this.category = category;
finalMapSearchUrl += Uri.encode(mapUrlParam);
Log.d(TAG,"Final map URL : " + finalMapSearchUrl);
}
private PlaceObject(Parcel in) {
name = in.readInt();
description = in.readInt();
locationDistance = in.readString();
category = in.readInt();
}
public static final Creator<PlaceObject> CREATOR = new Creator<PlaceObject>() {
#Override
public PlaceObject createFromParcel(Parcel in) {
return new PlaceObject(in);
}
#Override
public PlaceObject[] newArray(int size) {
return new PlaceObject[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(name);
parcel.writeInt(description);
parcel.writeString(locationDistance);
parcel.writeInt(category);
}
public int getName() {
return name;
}
public int getDescription() {
return description;
}
public String getLocationDistance() {
return locationDistance;
}
public int getCategory() {
return category;
}
public String getMapSearchUrl() {
Log.d(TAG,"finalMapSearchUrl = " + finalMapSearchUrl);
return finalMapSearchUrl; //TODO:sp figure out why the variable's value gets lost after the constructor is done
}
}
Because you're simply getting the base url and not the one Parceled.
Solution:
Add it to parcel and pay attention to the order of writing,
Like this:
private PlaceObject(Parcel in) {
name = in.readInt();
description = in.readInt();
category = in.readInt();
locationDistance = in.readString();
finalMapSearchUrl = in.readString();
}
and don't forget to fix this as well:
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(name);
parcel.writeInt(description);
parcel.writeInt(category);
parcel.writeString(locationDistance);
parcel.writeString(finalMapSearchUrl);
}
When i want to add item to favorite .. i write this code my program and access everywhere: Favorite.add(itemid);
When i want to add item to message i write this code my program and access everywhere: Message.add(itemid);
Two class have some methods. So how i can design this useful?
For example;
AbstractData.addFavorite(itemid);
AbstractData.addMessage(itemid);
or
AbstractData<Fav>.add(itemid);
AbstractData<SMS>.add(itemid);
or
Your opinion?
Thank for help and sory for my little english...
Favorite.class
public class Favorite {
static SparseArray<Fav> LIST = new SparseArray<>();
public static boolean add(int ID){
if(!check(ID)){
LIST.put(ID, new Fav(ID, DateFormat.getDateTimeInstance().format(new Date())));
return true;
}
return false;
}
public static void remove(int ID){
if(LIST.indexOfKey(ID) >= 0 )
LIST.remove(ID);
}
public static boolean check(int ID){return LIST.get(ID) != null;}
public static Fav get(int ID){return LIST.get(ID);}
public static void saveALL(){
AsyncTask.execute(new Runnable() {
#Override
public void run() {
Fav favorite;
for (int i = 0; i < LISTE.size(); i++) {
favorite = get(LISTE.keyAt(i));
if (favorite != null)
//Saving data to xml
}
}
});
Log.d("DONE", "Favorite LIST Saving");
}
}
Fav.class
public class Fav implements IModel{
private int ID;
private String DATE;
public Fav(int ID, String DATE) {
this.ID = ID;
this.DATE = DATE;
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public String getDate() {
return DATE;
}
public void setDate(String DATE) {
this.DATE = DATE;
}
}
Message.class
public class Message{
static SparseArray<SMS> LIST = new SparseArray<>();
public static boolean add(int ID){
if(!check(ID)){
LIST.put(ID, new SMS(ID, DateFormat.getDateTimeInstance().format(new Date())));
return true;
}
return false;
}
public static void remove(int ID){
if(LIST.indexOfKey(ID) >= 0 )
LIST.remove(ID);
}
public static boolean check(int ID){return LIST.get(ID) != null;}
public static SMS get(int ID){return LIST.get(ID);}
public static void saveALL(){
AsyncTask.execute(new Runnable() {
#Override
public void run() {
SMS message;
for (int i = 0; i < LISTE.size(); i++) {
message = get(LISTE.keyAt(i));
if (message != null)
//Saving data to xml
}
}
});
Log.d("DONE", "Message LIST Saving");
}
}
SMS.class
public class SMS implements IModel{
private int ID;
private String DATE;
public SMS(int ID, String DATE) {
this.ID = ID;
this.DATE = DATE;
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public String getDate() {
return DATE;
}
public void setDate(String DATE) {
this.DATE = DATE;
}
}
IModel.class
public interface IModel {
int getID();
void setID(int ID);
String getDate();
void setDate(String DATE);
}
In my opinion...
Don't over-design your models.
Don't make your add and remove methods static, it will eventually leave you with headaches. You want your constructor to initialize your object.
Either use a Singleton Pattern to get a single instance of your manager object, or
Keep your manager class as a local variable in your Application class, make an access method for it, initialize it in onCreate().
Personally I've started to ditch the getter/setter pattern in favour of public fields, particularly if they're final like in enums. I know this is supposed to be ugly but... I don't care as long as it's convenient =)
So...
public class MyApplication extends Application
{
private static MyApplication instance;
private FavouritesManager favouritesManager;
public static getMyApplicationInstance ()
{
return instance;
}
public void onCreate ()
{
instance = this;
favouritesManager = new FavouritesManager(this); // You may want it to have a Context...
}
}
public class FavouritesManager
{
private Map<Integer,Favourites> favorites;
public FavouritesManager ()
{
load();
}
public void add ( Favourite favourite )
{
favourites.put(favourite.id, favourite);
}
public boolean contains ( int favouriteId )
{
favourites.contaisKey(favouriteId);
}
private void load ()
{
favourites = new HashMap<>();
// Maybe deserialize json from SharedPreferenecs?
}
public List<Favorite> getAll ()
{
// Return all Favourites, sorted by their SortOrder.
}
public Favorite create ( String name )
{
// Maybe a factory method that generates an unused id and returns a new Favourite instance?
}
}
public Favourite
{
public final int id;
public final Date createDate;
public String name;
public int sortOrder;
public Favorite ( int id, String name, int sortOrder )
{
this.id = id;
this.createDate = Date();
this.name = name;
this.sortOrder = sortOrder;
}
}
public class MyActivity extend Activity
{
protected void onCreate ( Bundle savedInstanceState )
{
FavouritesManager favmanager = MyApplication.getMyApplicationInstance().getFavoritesManager();
}
{
}
Make your classes Message and SMS implement the same interface IModel. Then, when you implement your methods (e.g. add()) and want them to accept both Message and SMS objects, use the base interface in your method signature:
public class AbstractData {
public static void add(final IModel data) { // <- Use interface here!
// ...
}
}
Now you can add objects this way:
Message msg = new Message();
AbstractData.add(msg);
SMS sms = new SMS();
AbstractData.add(sms);
I have custom class that implements Parcelable and I use it as custom arraylist.
When I use putParcelableArrayListExtra and 400 rows it works fine, but 1000 rows it does not. I have black screen and app locks up. What is wrong?
EDIT:
I sent it here and I don't use it in another Activity.
Intent intent = new Intent().setClass(getApplicationContext(), ArtActivity.class);
intent.putParcelableArrayListExtra ("mylist", list);
startActivityForResult(intent, SECONDARY_ACTIVITY_REQUEST_CODE);
My array:
ArrayList<Piece> list = new ArrayList<Piece>();
It is my Class:
public class Piece implements Parcelable {
private String id;
private String name;
private int type;
private String text;
private String mp3;
public Piece (String id,String name,int type)
{
this.id=id;
this.name=name;
this.type=type;
}
public Piece(Piece ele)
{
this.id=ele.id;
this.name=ele.name;
this.type=ele.type;
this.text=ele.text;
}
public Piece (Parcel in)
{
id = in.readString ();
name = in.readString ();
type = in.readInt();
text= in.readString();
mp3=in.readString();
}
public static final Parcelable.Creator<Piece> CREATOR
= new Parcelable.Creator<Piece>()
{
public Piece createFromParcel(Parcel in)
{
return new Piece(in);
}
public Piece[] newArray (int size)
{
return new Piece[size];
}
};
public void makeText(String text)
{
this.text=text;
}
public void makeMp3(String mp3)
{
this.mp3= mp3;
}
public String getMp3()
{
return this.mp3;
}
public String getId()
{
return id;
}
public String getName()
{
return name;
}
public int getType()
{
return type;
}
public String getText()
{
return text;
}
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString (id);
dest.writeString (name);
dest.writeInt(type);
dest.writeString (text);
dest.writeString (mp3);
}
}
I do not believe you should be using parcelable in this case. I would either access the data statically (if you only intend to have one persistent instance of the data), or use a caching system to hold onto the data.
This is an example of a publicly available static variable:
public static List<Piece> list;
It is accessible from everywhere in your app that has visibility of the class.
However, doing this is very messy and is considered a bad practice. Alternatively, you can create an object to manage the data for you as a static class or singleton:
public class MyListManager {
private static List<Piece> mList;
public static List<Piece> getMyList() {
return mList;
}
public static void setList(List<Piece> list) {
mList = list;
}
}
Alternatively, you can implement some kind of a caching system to manage your data.