i have a growing arraylist with a custom object, for it to grow i need to save it so it doesn't get cleared, but even after implementing parcelable still doesn't work. did i implement parcelble wrong? all code works apart from being able to save my arraylist, if some one could help it will be a great help
//class
public class team implements Parcelable {
// Defining Activity class to use
private Activity activity;
// Defining text box
LinearLayout lay;
View Tbox;
// Members Defining
String teamname;
String teacher;
ArrayList<Players> members = new ArrayList<Players>();
public team(Activity activity, String teamname, String teacher) {
// To be able to use activity
this.activity = activity;
// Normal things to define
this.teamname = teamname;
this.teacher = teacher;
// initialize the lay and Tbox variables
lay = activity.findViewById(R.id.Scontainer);
Tbox = activity.getLayoutInflater().inflate(R.layout.text_box_output, null);
}
public void addtext() {
// add text to the layout and view
TextView title = Tbox.findViewById(R.id.daTeam);
title.setText(teamname);
lay.addView(Tbox);
}
//bs
protected team(Parcel in) {
teamname = in.readString();
teacher = in.readString();
}
public static final Creator<team> CREATOR = new Creator<team>() {
#Override
public team createFromParcel(Parcel in) {
return new team(in);
}
#Override
public team[] newArray(int size) {
return new team[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(#NonNull Parcel parcel, int i) {
parcel.writeString(teamname);
parcel.writeString(teacher);
}
}
//mainactivity
public class MainActivity extends AppCompatActivity {
ArrayList<team> listofteams ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null ) {
listofteams = savedInstanceState.getParcelableArrayList("key");
}
else{
listofteams = new ArrayList<team>();
}
setContentView(R.layout.sports_screen);
//sending out variable
Intent intent = new Intent (this, Creating_Class_main.class);
Activity ma = this;
//names
Intent MB = getIntent();
String Classinp = MB.getStringExtra("strC");
String tchinp = MB.getStringExtra("strT");
//adding team
team sportsteam;
System.out.println(listofteams);
boolean flag = MB.getBooleanExtra("flag", false);
if (flag){
sportsteam = new team(ma, Classinp,tchinp);
listofteams.add(sportsteam);
System.out.println(listofteams);
}
}
//saveing layout
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putParcelableArrayList("key", listofteams);
super.onSaveInstanceState(outState);
}
}
It's happening for 0.08% of our users.
One of the crashes happening on Samsung Galaxy S10 running Android 11
It's not crashing on my Samsung Galaxy S10 running Android 11 though!
Does anyone know why?
Line where it crashes
Photo[] photoArray = (Photo[]) bundle.getParcelableArray(EXTRA_PHOTOS);
1st finding
Photo photo1 = new Photo(231, "url", "photoid", "profilid", "caption");
Parcelable[] parcelables1 = new Parcelable[]{photo1};
Photo[] array = (Photo[]) parcelables1;
Throws ClassCastException
This couple with the fact that Bundle#getParcelableArray only returns a Parcelable array, not the the concrete class Photo array explains why the crash is expected
But why is it only happening for some users only?
2nd finding
This post claims that getParcelableArray() won't work, only getParcelableArrayListExtra() or individual casting will work but the why is unclear to me
3rd finding
So I've learnt that downcasting arrays is not supposed to work in Java or Kotlin, at least not in the way Android Bundle do it.
The reason why getParcelableArrayListExtra() works is because it assume generic type and did work to handle the type.
Question remains: how come getParcelableArray() works nicely in my real device and emulator? Is there some black magic hidden in plain sight here?
Code below
Photo.java
public class Photo implements Serializable, Model, Parcelable {
private String caption;
private String id, idProfile;
private int position;
private String iphoneFullscreen;
public Photo(int position, String url, String photoId, String profileId, String caption) {
iphoneFullscreen = url;
this.position = position;
this.id = photoId;
idProfile = profileId;
this.caption = caption;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.caption);
dest.writeString(this.id);
dest.writeString(this.idProfile);
dest.writeInt(this.position);
dest.writeString(this.iphoneFullscreen);
}
protected Photo(Parcel in) {
this.caption = in.readString();
this.id = in.readString();
this.idProfile = in.readString();
this.position = in.readInt();
this.iphoneFullscreen = in.readString();
}
public static final Parcelable.Creator<Photo> CREATOR = new Parcelable.Creator<Photo>() {
#Override
public Photo createFromParcel(Parcel source) {
return new Photo(source);
}
#Override
public Photo[] newArray(int size) {
return new Photo[size];
}
};
}
How it's provided and consumed
DialogFragmentPhotoGallery.java
public static DialogFragment newInstance(
Photo[] photos) {
DialogFragmentPhotoGallery dialogFragmentPhotoGallery = new DialogFragmentPhotoGallery();
Bundle args = new Bundle();
args.putParcelableArray(DialogFragmentPhotoGallery.EXTRA_PHOTOS, photos);
dialogFragmentPhotoGallery.setArguments(args);
return dialogFragmentPhotoGallery;
}
public View onCreateView(
#NonNull LayoutInflater inflater,
ViewGroup parent,
Bundle savedInstanceState) {
if (getArguments() != null) {
Photo[] photos = (Photo[]) getArguments().getParcelableArray(EXTRA_PHOTOS); // <-- CRASH
// do things with photos
}
I am crafting a non profit charity app. Despite I have checked many questions in stack and google, i could not solve the problem.
I have 3 classes:
- BaseCell implements Parcelable (Base class)
- Needy extends BaseCell
- UserBasket class which hold the list of all classes extend BaseCell
Problem
I am holding Needy classes with Arraylist in UserBasket class. When i send it to another activity, if i add 1 item to the UserBasket i am getting ridiculous result(Missing or wrong characters) and if i add more than 1 item then i am getting exception.
I need to deliver UserBasket class(list of needy items) to the payment activity so i can calculate the total price for charity and perform necessary actions.
public abstract class BaseCell implements Parcelable {
String imageUrl;
int percentageOfCollectedDonation;
String needyTitle;
String needyDescription;
protected String category;
protected int amountOfCollectedDonation=0;
protected int amountOfTargetDonation=0;
protected int amountOfDonater=0;
protected int drawableID;
protected String campaignCode;
protected int maxInstallmentNumber;
int price;
public String getCellType() {
return cellType;
}
protected String cellType ;
/**
* How many of this campaign purchased by user
* */
protected int userPurchaseAmount = 1;
protected BaseCell(String cellType)
{
this.cellType = cellType;
}
protected BaseCell(Parcel in)
{
drawableID = in.readInt();
price = in.readInt();
imageUrl = in.readString();
needyTitle = in.readString();
needyDescription = in.readString();
category = in.readString();
campaignCode = in.readString();
maxInstallmentNumber = in.readInt();
userPurchaseAmount = in.readInt();
}
public static final Parcelable.Creator<BaseCell> CREATOR = new Parcelable.Creator<BaseCell>() {
#Override
public BaseCell createFromParcel(Parcel in) {
String cellType = in.readString();
BaseCell baseCell = null;
if (cellType.equals("Needy"))
{
baseCell = (Needy)new Needy(in);
}else
if (cellType.equals("Qurban"))
{
baseCell = (Qurban)new Qurban(in);
}
return baseCell;
}
#Override
public BaseCell[] newArray(int size) {
return new BaseCell[size];
}
};
public void writeToParcel(Parcel out, int flags) {
out.writeString(getCellType());
}
public BaseCell(String imageUrl, int drawableID, String needyTitle, String needyDescription, int amountOfCollectedDonation, int amountOfTargetDonation, int amountOfDonater, String category,String campaignCode, int maxInstallmentNumber, int price)
{
this.imageUrl = imageUrl;
this.drawableID = drawableID;
this.needyTitle = needyTitle;
this.needyDescription = needyDescription;
this.amountOfCollectedDonation = amountOfCollectedDonation;
this.amountOfTargetDonation = amountOfTargetDonation;
this.amountOfDonater = amountOfDonater;
this.category = category;
this.campaignCode = campaignCode;
this.maxInstallmentNumber = maxInstallmentNumber;
this.price= price;
}
}
Needy
public class Needy extends BaseCell {
protected Needy(Parcel in) {
super(in);
cellType ="Needy";
}
public static final Parcelable.Creator<Needy> CREATOR = new Parcelable.Creator<Needy>() {
#Override
public Needy createFromParcel(Parcel in) {
return new Needy(in);
}
#Override
public Needy[] newArray(int size) {
return new Needy[size];
}
};
public Needy(String imageUrl, int drawableID, String needyTitle, String needyDescription, int amountOfCollectedDonation, int amountOfTargetDonation, int amountOfDonater, String category, String campaignCode, int maxInstallmentNumber, int price) {
super(imageUrl, drawableID, needyTitle, needyDescription, amountOfCollectedDonation, amountOfTargetDonation, amountOfDonater, category, campaignCode, maxInstallmentNumber,price);
cellType = "Needy";
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getCellType());
super.writeToParcel(dest,flags);
dest.writeInt(drawableID);
dest.writeInt(price);
dest.writeString(imageUrl);
dest.writeString(needyTitle);
dest.writeString(needyDescription);
dest.writeString(category);
dest.writeString(campaignCode);
dest.writeInt(maxInstallmentNumber);
dest.writeInt(userPurchaseAmount);
}
#Override
public void setUserPurchaseAmount(int userPurchaseAmount) {
super.setUserPurchaseAmount(userPurchaseAmount);
}
}
UserBasket
public class UserBasket implements Parcelable{
List<BaseCell> userBasket;
/**
* holds all items to be purchased
* */
public UserBasket(List<BaseCell> userBasket) {
this.userBasket = userBasket;
}
public UserBasket() {
userBasket = new ArrayList<>();
}
protected UserBasket(Parcel in) {
super();
setUserBasket(new ArrayList<BaseCell>());
userBasket = in.createTypedArrayList(BaseCell.CREATOR);
//in.readTypedList(userBasket,BaseCell.CREATOR);
}
public static final Parcelable.Creator<UserBasket> CREATOR = new Parcelable.Creator<UserBasket>() {
#Override
public UserBasket createFromParcel(Parcel in) {
return new UserBasket(in);
}
#Override
public UserBasket[] newArray(int size) {
return new UserBasket[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(userBasket);
}
public List<BaseCell> getUserBasket() {
return userBasket;
}
public void setUserBasket(List<BaseCell> userBasket) {
this.userBasket = userBasket;
}
/**
* Add to the basket list
* */
public void add(Needy donation) {
if (donation != null)
userBasket.add(donation);
}
/**
* Remove from basket list
* */
public void remove(int position)
{
if (userBasket.size()>0)
userBasket.remove(position);
}
}
sending userBasket arrayList with items from MainActivity
Navigate.navigateToPaymentPayuStart
(MainActivity.this,userBasket,"basket");
// userBasket arrayList with "basket" key
Receiving UserBasket in paymentPayu activity
UserBasket userBasket = getIntent().getParcelableExtra("basket");
How am i going to get UserBasket properly in paymentPayuActivity.
I appreciate for the help
Thank you.
It does seem like you are handling the Parcelable implementation wrong. e.i. you are reading some of the variables from the Parcel twice, which isn't allowed. So to improve this, we'll try to make your code a bit simpler. As Needy doesn't actually have any variables, it seems better to let BaseCell handle all of the parcelable implementation, i've tried to create a mock for you, so depending on the rest of your code it might need a bit of tweaking.
First i've removed all of the Parcelable implementation in Needy and is just pointing it's CREATOR to BaseCell.
public class Needy extends BaseCell {
protected Needy(Parcel in) {
super(in);
cellType ="Needy";
}
// Since Needy doesn't actually store any variables, we don't need a Creator for it.
// Just point it to BaseCell.CREATOR and let it handle it
public static final Parcelable.Creator<BaseCell> CREATOR = BaseCell.CREATOR;
public Needy(String imageUrl, int drawableID, String needyTitle, String needyDescription, int amountOfCollectedDonation, int amountOfTargetDonation, int amountOfDonater, String category, String campaignCode, int maxInstallmentNumber, int price) {
super(imageUrl, drawableID, needyTitle, needyDescription, amountOfCollectedDonation, amountOfTargetDonation, amountOfDonater, category, campaignCode, maxInstallmentNumber,price);
cellType = "Needy";
}
}
And then we'll let BaseCell handle all of the Parcelable implementation, like so:
public abstract class BaseCell implements Parcelable {
/**
* ALL OF YOUR VARIABLES, GETTERS, SETTERS AND CONSTRUCTORS GOES HERE
*/
#Override
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<BaseCell> CREATOR = new Parcelable.Creator<BaseCell>() {
#Override
public BaseCell createFromParcel(Parcel in) {
String cellType = in.readString();
if (cellType.equals("Needy")) {
return (Needy)new Needy(in);
} else if (cellType.equals("Qurban")) {
return (Qurban)new Qurban(in);
}
return null;
}
#Override
public BaseCell[] newArray(int size) {
return new BaseCell[size];
}
};
protected BaseCell(Parcel in) {
drawableID = in.readInt();
price = in.readInt();
imageUrl = in.readString();
needyTitle = in.readString();
needyDescription = in.readString();
category = in.readString();
campaignCode = in.readString();
maxInstallmentNumber = in.readInt();
userPurchaseAmount = in.readInt();
}
public void writeToParcel(Parcel out, int flags) {
// cellType written first, and read by Creator
out.writeString(cellType);
// the rest is read by the BaseCell constructor
out.writeInt(drawableID);
out.writeInt(price);
out.writeString(imageUrl);
out.writeString(needyTitle);
out.writeString(needyDescription);
out.writeString(category);
out.writeString(campaignCode);
out.writeInt(maxInstallmentNumber);
out.writeInt(userPurchaseAmount);
}
}
I am having some hard time trying to figure out how to write data with a Parcel object, I am new using this class and I've been doing some research but don't understand how to, here is the parcelable class
public class Item implements Parcelable {
private String iItemName;
private String iType;
private String iSerial;
private String iRetailer;
private String iLocation;
private String iValue;
private String iDescription;
public Item() {
super();
}
public Item (Parcel in) {
super();
this.iItemName = in.readString();
this.iType = in.readString();
this.iSerial = in.readString();
this.iRetailer = in.readString();
this.iLocation = in.readString();
this.iValue = in.readString();
this.iDescription = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(getItemName());
parcel.writeString(getType());
parcel.writeString(getSerial());
parcel.writeString(getRetailer());
parcel.writeString(getLocation());
parcel.writeString(getValue());
parcel.writeString(getDescription());
}
public static final Parcelable.Creator<Item> CREATOR = new Parcelable.Creator<Item>(){
#Override
public Item createFromParcel(Parcel source) {
Item item = new Item();
item.iItemName = source.readString();
return item;
}
public Item [] newArray(int size) {
return new Item[size];
}
};
public String getItemName() {
return iItemName;
}
public void setItemName(String iItemName) {
this.iItemName = iItemName;
}
my question is if I want to create a new Item object I need to send as a parameter a Parcel Object am I right? so I can do something like:
String name = getString("name");
// how to add name to the parcel object?
Parcel parcel;
Item i = new Item(parcel);
No you do not need to. Your object now has two constructors. You should create the object like normal and call its setter methods. You should avoid manually creating parcels and rather use writeValue() and readValue() methods.
// Create an item as usual
Item myItem = new Item();
myItem.setItemName("name");
// Add it to a parcel
Parcel parcel = Parcel.obtain();
parcel.writeValue(myItem);
// Read the item back from the parcel
parcel.setDataPosition(0);
Item newItem = (Item) parcel.readValue(Item.class.getClassLoader());
// When you are finished with the parcel
parcel.recycle();
Usually you would create an object from a Parcel when receiving it from an Intent. In which case you would do the following.
// Create intent
Intent intent = new Intent(this, MyActivity.class);
Bundle itemBundle = new Bundle();
itemBundle.putParcelable("item_extra", myItem);
intent.putExtras(itemBundle);
startActivity(intent);
// In the activities onCreate(Bundle savedInstanceState)
Item myItem = getIntent().getParcelableExtra("item_extra");
I have an Parcelable object called Book and another called Author. I can't tell why the object constructor for Book is not working. The first bit of code is where i try to make it so I can send it to a parent activity. The values were checked before, and when I do the .toString() method on book, I get null Price: null
Activity Code
EditText editText = (EditText) findViewById(R.id.search_title);
String title = editText.getText().toString();
editText = (EditText) findViewById(R.id.search_author);
String author = editText.getText().toString();
editText = (EditText) findViewById(R.id.search_isbn);
int isbn = Integer.parseInt(editText.getText().toString());
...
Parcel p = Parcel.obtain();
p.writeInt(isbn);
p.writeString(title);
p.writeString(author);
p.writeString(editText.getText().toString());
p.writeString("$15.00");
Intent intent = new Intent();
Book book = new Book(p);
System.out.println(book.toString());
Book.java
public class Book implements Parcelable {
private int id;
private String title;
private ArrayList<Author> authors = new ArrayList<Author>();
//private int Aflags;
private String isbn;
private String price;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(id);
out.writeString(title);
out.writeTypedList(authors);
out.writeString(isbn);
out.writeString(price);
}
public Book(Parcel in) {
id = in.readInt();
title = in.readString();
in.readTypedList(authors, Author.CREATOR);
isbn = in.readString();
price = in.readString();
}
public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
public Book createFromParcel(Parcel in) {
return new Book(in);
}
public Book[] newArray(int size) {
return new Book[size];
}
};
#Override
public String toString()
{
return title + " Price: " + price;
}
}
Author.java
public class Author implements Parcelable {
// NOTE: middleInitial may be NULL!
public String firstName;
public String middleInitial;
public String lastName;
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(firstName);
if (middleInitial.length() == 0)
out.writeString(middleInitial);
out.writeString(lastName);
}
private Author(Parcel in)
{
firstName = in.readString();
if (in.dataSize() == 2)
middleInitial = in.readString();
if (in.dataSize() == 1)
lastName = in.readString();
}
public static final Parcelable.Creator<Author> CREATOR = new Parcelable.Creator<Author>() {
public Author createFromParcel(Parcel in) {
return new Author(in);
}
public Author[] newArray(int size) {
return new Author[size];
}
};
#Override
public int describeContents() {
return 0;
}
}
Parcel p = Parcel.obtain();
p.writeInt(isbn);
p.writeString(title);
p.writeString(author); // Here i think u need to write list of author and not string
p.writeString(editText.getText().toString());
p.writeString("$15.00");
Intent intent = new Intent();
Book book = new Book(p);
System.out.println(book.toString());
/*****Edited answer ******/
//HERE u go mate this should work, tested code
//You need to parse the author text then
Parcel p = Parcel.obtain();
p.writeInt(23); // isbn
p.writeString("sometitle");
// List<String> data = new List<String>();//parseAuthor(author); // function dependent on what u get
Parcel auth = Parcel.obtain();
auth.writeString("firstname"); // firstname
auth.writeString("middle"); // middle
auth.writeString("lastname"); // lastname
auth.setDataCapacity(3);
auth.setDataPosition(0);
Author a = Author.CREATOR.createFromParcel(auth);
ArrayList<Author> authors = new ArrayList<Author>();
authors.add(a);
p.writeTypedList(authors);
p.writeString("something");
p.writeString("$15.00");
p.setDataPosition(0);
Intent intent = new Intent();
Book book = Book.CREATOR.createFromParcel(p);
System.out.println(book.toString());
Hi so I just gave up and made a new constructor that doesn't use Parcels.
But what was written below p.setDataPosition(0); may work as well for future users