Intent extras seem to get corrupted - android

Boy, this is a weird one.
I'm sending an intent to a service.
public void updatePortfolio(VehiclePortfolio vehiclePortfolio) {
GenericParcel gp = new GenericParcel(vehiclePortfolio);
Intent apiIntent = new Intent(context, ApiRequestService.class);
apiIntent.putExtra(Constants.ARG_REQUEST, Constants.REQUEST_UPDATE_PORTFOLIO);
apiIntent.putExtra(Constants.ARG_VEHICLE_PORTFOLIO, gp);
// Try getting object back here
//gp = apiIntent.getParcelableExtra(Constants.ARG_VEHICLE_PORTFOLIO);
VehiclePortfolio vp = (VehiclePortfolio)gp.getObject();
String s = apiIntent.getStringExtra(Constants.ARG_REQUEST);
vehiclePortfolio = (VehiclePortfolio) gp.getObject();
// .putExtra(Constants.ARG_VEHICLE_PORTFOLIO, b);
context.startService(apiIntent);
}
When I check the extras in the intent at the end of this function they look fine as shown below.
mMap HashMap (id=830037731672)
[0] HashMap$HashMapEntry (id=830037731800)
key "ARG_VEHICLE_PORTFOLIO" (id=830038543392)
value GenericParcel (id=830038204888)
o VehiclePortfolio (id=830038244704)
configuration VehicleConfiguration (id=830038258216)
id "1375379159508" (id=830038245672)
optionals VehiclePortfolio$_Fields[5] (id=830038244744)
priceReport VehiclePriceReport (id=830038312960)
quotes ArrayList (id=830038417704)
timestamp "2013-08-01T17:46:31.000Z" (id=830038536424)
[1] HashMap$HashMapEntry (id=830037731768)
key "ARG_REQUEST" (id=830037687416)
value Integer (id=830019251512)
value 6
Then, when the service receives the intent, this is what the extras look like. Notice that the vehiclePortfolio has been overwritten on top of ARG_REQUEST extra and the key and value have been swapped. (What?!?)
mMap HashMap (id=830038833832)
[0] HashMap$HashMapEntry (id=830039001656)
key VehiclePortfolio (id=830038934408)
configuration VehicleConfiguration (id=830038936272)
id "1375379159508" (id=830038936128)
optionals null
priceReport VehiclePriceReport (id=830038941176)
quotes ArrayList (id=830038963264)
timestamp "2013-08-01T17:46:31.000Z" (id=830039001424)
value "ARG_REQUEST" (id=830039001576)
[1] HashMap$HashMapEntry (id=830038834568)
key "ARG_VEHICLE_PORTFOLIO" (id=830038833888)
value GenericParcel (id=830038834512)
o Parcel (id=830037350528)
mNativePtr 1891558544
mOwnsNativeParcelObject true
mStack null
Below is the code for GenericParcel which I suspect to be the culprit. If I do a test and pass a string in place of the complex object inside a GenericParcel, behavior is as expected.
public class GenericParcel implements Parcelable {
private Object o;
public GenericParcel(Object in) {
o = in;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeValue(o);
}
public Object getObject() {
return o;
}
public static final Creator<GenericParcel> CREATOR = new Creator<GenericParcel>() {
public GenericParcel createFromParcel(Parcel source) {
return new GenericParcel(source);
}
public GenericParcel[] newArray(int size) {
return new GenericParcel[size];
}
};
}

I think your implementation of your Parcelable object is not correct. You should have a constructor that takes as its only argument a Parcel (not an Object) and you should be reading values from the Parcel in the same order you wrote them to the Parcel in writeToParcel().
public class GenericParcel implements Parcelable {
private Object o;
public GenericParcel(Parcel in) {
o = in.readValue(null);
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeValue(o);
}
// the rest removed for brevity
}

Related

Read and Write Long Object in Android Parcelable Class

If say I have following with a long object. Does below example demonstrate correct way of reading and writing Long object?
Class MyClass implements Parcelable {
private Long aLongObject;
public static final Creator<MyClass> CREATOR = new Creator<MyClass>() {
#Override
public MyClass createFromParcel(Parcel in) {
return new MyClass(in);
}
#Override
public MyClass[] newArray(int size) {
.....
}
};
protected MyClass(Parcel in) {// reading Parcel
super(in);
aLongObject = in.readLong(); // correct way to ready Long object?
}
#Override
public void writeToParcel(#NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeLong(aLongObject); // is this correct way to send Long?
}
}
The problem with your approach is that a Long value may be null but the Parcel methods only take/ return values of the primitive data type long, see the documentation for details. So you need a workaround to store a Long value.
I like to use a int to indicate whether my Long value is null (you can only store boolean arrays no single boolean values) and a long to store the numerical value if it isn't:
Writing to the Parcel
int indicator = (aLongObject == null) ? 0 : 1;
long number = (aLongObject == null) ? 0 : aLongObject;
dest.writeInt(indicator);
dest.writeLong(number);
Reading from the Parcel
// NOTE: reading must be in the same order as writing
Long aLongObject;
int indicator = in.readInt();
long number = in.readLong();
if(indicator == 0){
aLongObject = null;
}
else{
aLongObject = number;
}
You can simply use
Write
dest.writeValue(this.aLongObject);
Read
this.aLongObject = (Long)in.readValue(Long.class.getClassLoader());
writeValue and readValue handle null gracefully.
Please refer to https://stackoverflow.com/a/10769887/72437

Unmarshalling unknown type code XXXXX at offset YYY when using getIntent().getExtras().getInt() [duplicate]

This question already has answers here:
java.lang.RuntimeException: Parcel android.os.Parcel: Unmarshalling unknown type code
(2 answers)
Closed 5 years ago.
I'm trying to pass an int value from activity A to activity B.
Activity A:
Intent intent = new Intent(ActivityA.this, ActivityB.class);
intent.putExtra("list_size", list.size());
for (int i = 0; i < list.size(); i++) {
intent.putExtra("account" + i, accountList.get(i));
}
startActivityForResult(intent, 2);
Activity B:
private void init() {
Intent intent = getIntent();
int listSize = intent.getIntExtra("list_size", 0); // Error thrown here
for (int i = 0; i < listSize; i++) {
newList.add((Account) intent.getParcelableExtra("account" + i));
}
}
Account (this is the list item):
public class Account implements Parcelable {
private Long accountId;
private String accountName;
private Set<String> followedAccountsIds = new HashSet<>();
private Set<String> followersAccountsIds = new HashSet<>();
private Set<Integer> likedTagsIds = new HashSet<>();
private Set<Post> postsByAccount = new HashSet<>();
public Account() {
}
public Account(Long accountId, String accountName, Set<String> followedAccountsIds,
Set<String> followersAccountsIds, Set<Integer> likedTagsIds, Set<Post> postsByAccount) {
this.accountId = accountId;
this.accountName = accountName;
this.followedAccountsIds = followedAccountsIds;
this.followersAccountsIds = followersAccountsIds;
this.likedTagsIds = likedTagsIds;
this.postsByAccount = postsByAccount;
}
// Omitted getters and setters for brevity
protected Account(Parcel in) {
if (in.readByte() == 0) {
accountId = null;
} else {
accountId = in.readLong();
}
accountName = in.readString();
}
public static final Creator<Account> CREATOR = new Creator<Account>() {
#Override
public Account createFromParcel(Parcel in) {
return new Account(in);
}
#Override
public Account[] newArray(int size) {
return new Account[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeLong(accountId);
parcel.writeString(accountName);
}
}
Error that is thrown:
Caused by: java.lang.RuntimeException: Parcel android.os.Parcel#8b4252e: Unmarshalling unknown type code 6357091 at offset 140
at android.os.Parcel.readValue(Parcel.java:2453)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2727)
at android.os.BaseBundle.unparcel(BaseBundle.java:269)
at android.os.BaseBundle.getInt(BaseBundle.java:867)
at android.content.Intent.getIntExtra(Intent.java:6637)
at com.david.songshareandroid.activities.ActivityB.init(ActivityB.java:33)
at com.david.songshareandroid.activities.ActivityB.onCreate(ActivityB.java:28)
at android.app.Activity.performCreate(Activity.java:6912)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2877)
In ActivityB when intent.getIntExtra("list_size", 0) is invoked, the error above occurs. If I remove the for loop in ActivityA, that is the objects are not getting passed to ActivityB, then the error does not occur anymore.
You are putting something but getting something else.
You are putting an Int
intent.putExtra("list_size", list.size());
Now on Target Activity do this:
Intent intent = getIntent();
int number = intent.getIntExtra("list_size",0);
and your SomeObject class must implement Parceable interface
First you taking Bundle Extras using intent.getExtras() which returns you bundle object which contains key-value pairs, and then you trying to find pair with key list_size which is not in there. So you should use intent.getIntExtra() instead.
UPD
I don't think that your parcel implementation should work because of Sets. Use Set.toArray() method, then in Parcel.writeTypedArray write it to the parcel.

intent.hasExtra("meta") throw bad parcelable exception

Hi in my app I see an exception in this line of code
intent.hasExtra("meta")
this is my exception
Caused by android.os.BadParcelableException
android.os.Parcel.readParcelableCreator (Parcel.java:2436)
android.os.Parcel.readParcelable (Parcel.java:2358)
android.os.Parcel.readValue (Parcel.java:2264)
android.os.Parcel.readArrayMapInternal (Parcel.java:2614)
android.os.BaseBundle.unparcel (BaseBundle.java:221)
android.os.BaseBundle.containsKey (BaseBundle.java:269)
android.content.Intent.hasExtra (Intent.java:6002)
Unable to start activity ComponentInfo{xxx.Activity}: >android.os.BadParcelableException: Parcelable protocol requires a ?Parcelable.Creator object called CREATOR on class Meta
I cannot understand how could this happen I'm just asking for existing of a key in an intent extras but it throws an exception.
For testing, how can this scenario happen? I create a test app and create a parcelable object and check for meta in intent but my app works correctly and does not throw the exception.
//test case
Intent intent=new Intent();
intent.putExtra("META",new A());
Log.d(TAG, "onCreate:
intent.hasExtra(\"META\")="+intent.hasExtra("META"));
//this log work without exception so why i get exception in my original app?
static class A implements Parcelable{
String d="0dsfa";
int a=10;
public A(){
}
// the order of reading and write parcelable is wrong
// but I want to see that's cause of exception, which my test shows
// that's not my problem
protected A(Parcel in) {
a = in.readInt();
d = in.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(d);
dest.writeInt(a);
}
private static final Creator<A> CREATOR = new Creator<A>() {
#Override
public A createFromParcel(Parcel in) {
return new A(in);
}
#Override
public A[] newArray(int size) {
return new A[size];
}
};
#Override
public int describeContents() {
return 0;
}
}

ArrayList and Parcelable

I need to "transfer" an ArrayList of custom class from one entity to another. I know that I need to implement Parcelable interface.
This is my custom class.
public class cSportsList implements Parcelable {
boolean checked;
String name;
cSportsList(boolean check, String name_) {
checked = check;
name = name_;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
//Non posso passare un booleano e non posso fare il cast boolean -> int
if (checked) {
dest.writeInt(1);
}
else dest.writeInt(0);
dest.writeString(name);
}
public static final Parcelable.Creator<cSportsList> CREATOR = new Parcelable.Creator<cSportsList>() {
public cSportsList createFromParcel(Parcel in) {
return new cSportsList(in);
}
public cSportsList[] newArray(int size) {
return new cSportsList[size];
}
};
private cSportsList(Parcel in) {
if (in.readInt() == 1) {
checked = true;
}
else {
checked = false;
}
name = in.readString();
}
}
And this is the code in entity "from"
//This is sportsMap: ArrayList<cSportsList> sportsMap = new ArrayList<cSportsList>();
Intent intent = new Intent(getApplicationContext(),WhatSportActivity.class);
intent.putParcelableArrayListExtra("sportsMap", (ArrayList<? extends Parcelable>) sportsMap); //I have tried with ArrayList<cSportsList> too.
this.startActivity(intent);
And this is the code in entity "to"
final Intent srcIntent = getIntent();
ArrayList<cSportsList> sportsMap = srcIntent.getParcelableExtra("sportsMap");
The problem is: in entity "To" sportsMap is null.
If I set "breakpoint" in "writeToParcel" and "cSportsList(Parcelable in)" functions I see that the code is executed for both functions.
Where is my error ?
Thanks. M.
While reading you need to use
srcIntent.getParcelableArrayListExtra("sportsMap");
To put into Intent use below code
intent.putParcelableArrayListExtra("sportsMap", sportsMap);
and to read it from intent, use
ArrayList<cSportsList> sportsMap = srcIntent.getParcelableArrayListExtra("sportsMap");
Read similar solution at Pass ArrayList<? implements Parcelable> to Activity
Use the below code
sportsMap = srcIntent.getParcelableArrayListExtra("sportsMap");
You should use :
ArrayList<cSportsList> sportsMap = srcIntent.getParcelableArrayListExtra("sportsMap");
You can also use Serialization for the same.
public class cSportsList implements Serializable
for put:
intent.putExtra("LIST",list);
for get:
(ArrayList<>)intent.getSerializableExtra("LIST");
Try passing Arraylist instead of casting it like this:
Intent intent = new Intent(getApplicationContext(),WhatSportActivity.class);
intent.putParcelableArrayListExtra("sportsMap", sportsMap);
startActivity(intent);
In WhatSportActivity,
final Intent srcIntent = getIntent();
ArrayList<cSportsList> sportsMap = srcIntent.getParcelableExtra("sportsMap");
In case you still have problems,please try implementing Parceable by using "Parceable"plugin as It reduces the error in using Parceable lists.

Parcelable how to use the 'KEY' value when receiving all the information?

I'm making an Android application and I would like to send an ArrayList to the next Activity, but I don't know how to do this with Parcelable.
For example: I got an int named as ID and a String named as Names. I use JSON for getting all informations from PHP and MySQL.
In the for-loop I add all those Names and ID to a class. But then I don't know how to write all these Names and ID into a bundle.putParcelableArrayList(KEY, ArrayList...);, because I don't know how to do this with the KEY value. Do I need to give the KEY value numbers or is there automatically one KEY?
class alleDeelnemers implements Parcelable {
int id;
String name;
/* GETTER AND SETTER */
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(volgnummer);
}
public alleDeelnemers(Parcel in) {
volgnummer = in.readString();
id = in.readInt();
}
// Creator
public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
public alleDeelnemers createFromParcel(Parcel in) {
return new alleDeelnemers(in);
}
public alleDeelnemers[] newArray(int size) {
return new alleDeelnemers[size];
}
};
}
Receiving data:
ArrayList<alleDeelnemers> deelnemers = new ArrayList<>();
for(int i=0; i < jArrayDeelnemer.length(); i++)
{
JSONObject json_data = jArrayDeelnemer.getJSONObject(i);
//class alleDeelnemers
deelnemer = new alleDeelnemers();
//ID
int ID = json_data.getInt("ID");
deelnemer.setId(ID);
//alle deelnemers
String name = json_data.getString("name ");
deelnemer.setName(name );
//toevoegen in de class
deelnemers.add(deelnemer);
}
error this line: deelnemer = new alleDeelnemers(); need to build a constructor.
The key is any name you would use to reference your ArrayList. Further in the started activity, you will use this key to retrieve the ArrayList. For example, in the initial activity, do
bundle.putParcelableArrayList("MY_ARRAY_LIST", deelnemers);
and then in the started activity, to retrieve it later
Bundle b = getIntent().getExtras();
ArrayList<alleDeelnemers> list = b.getParcelableArrayList("MY_ARRAY_LIST");
Note that the KEY used here is "MY_ARRAY_LIST". It is a better practice to use xml string constants or an interface for storing constant KEYS.
1.First create your alleDeelnemers class as Parcelable using plug-in
2 Sender Activity
Intent intent = new Intent(this, YourActivity.class);
intent.putExtra("mData", myArrayList);
3 Receiver Activity
myArrayList = getIntent().getParcelableExtra("mData")

Categories

Resources