Reading ArrayList in Parcelable - java

I have a class called SuperMedia that implements Parcelable. One of the fields of the class is an ArrayList children. When I create a Bundle and try to pass a "SuperMedia" object from one activity to another, all the fields get passed fine with the exception of the ArrayList "children" which just shows up as being empty every time.
In my first Activity I do:
Bundle a = new Bundle();
a.putParcelable("media",media); //media is an object of type "SuperMedia" and all the "children" have been initialized and added to the array
final Intent i = new Intent("com.tv.video.subcategories");
i.putExtra("subcategories", a);
On my Second Activity I do:
Intent i = getIntent();
Bundle secondBun = i.getBundleExtra("subcategories");
SuperMedia media = secondBun.getParcelable("media"); //For some reason the ArrayList"children" field shows up as empty.
Im not sure why this is happening. If anybody can guide me on the right path that would be greatly appreciated. Below is my SuperMedia class btw.
public class SuperMedia implements Parcelable{
public URI mthumb;
public String mTitle;
public ArrayList<SuperMedia> children = new ArrayList();
public SuperMedia(URI thumb, String title) {
this.mthumb = thumb;
this.mTitle = title;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString(mTitle);
dest.writeString(mthumb.toString());
dest.writeTypedList(children);
}
public static final Parcelable.Creator<SuperMedia> CREATOR = new Parcelable.Creator<SuperMedia>() {
public SuperMedia createFromParcel(Parcel in) {
return new SuperMedia(in);
}
public SuperMedia[] newArray(int size) {
return new SuperMedia[size];
}
};
private SuperMedia(Parcel in) {
mTitle = in.readString();
try {
mthumb = new URI(in.readString());
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
in.readTypedList(children, SuperMedia.CREATOR);
}
public SuperMedia(){
}
}

If you want simply pass object through intent then you can make SuperMedia Serializable no need to Parcelable.
public class SuperMedia implements Serializable{...}
put it as
Bundle a = new Bundle();
a.putSerializable("media",media);
and we get it as.
Intent i = getIntent();
Bundle secondBun = i.getBundleExtra("subcategories");
SuperMedia media = (SuperMedia)secondBun.getSerializable("media");
if you really needed Parcelable then may it help you.
Arraylist in parcelable object

Use Bundle's putParcellableArrayList for storing SuperMedia object
Bundle args = new Bundle();
args.putParcelableArrayList("media", "media");
and for restroring
getArguments().getParcelableArrayList("media");
This way will ensure bundle save your list objects as implemented in parcelable instance.
Also, be aware of using only ArrayList, other List subclasses not supported.

Related

Android. Passing this custom object to next Activity?

I have this custom object which I want to pass to a different Activity:
public class FindRouteOutputForDisplay {
public ArrayList<VertexDisplay> vertexDisplayArrayList;
public ArrayList<Integer> integerArrayList;
}
I tried this, but doesn't work.
Intent newIntent = new Intent(FirstActivity.this, SecondActivity.class);
FindRouteOutputForDisplay data = getMyData();
newIntent.putExtra("data", data); // Error
startActivity(newIntent);
Should I pass
public ArrayList<VertexDisplay> vertexDisplayArrayList;
public ArrayList<Integer> integerArrayList;
separately one-by-one? Any way to pass all of them at once?
You can try this solution.
public class FindRouteOutputForDisplay implements Serializable{
public ArrayList<VertexDisplay> vertexDisplayArrayList;
public ArrayList<Integer> integerArrayList;
}
Intent newIntent = new Intent(FirstActivity.this, SecondActivity.class);
FindRouteOutputForDisplay data = getMyData();
newIntent.putSerializable("data", data);
startActivity(newIntent);
If you have any errors on "putSerializable" so you can cast your object to Serializable in this way.
newIntent.putSerializable("data", (Serializable)data);
And in your activity just get your data by this
FindRouteOutputForDisplay data = getIntent().getSerializable("data");
Hope it helps.
Save your data in your application context class. Since this class is available across your application instance, you can get or set the variables defined inside this class from all activities. More info here
Change this :
startActivity(routeDetailIntent);
To :
startActivity(newIntent);
You should make the custom objects implement the Parcelable interface:
public class MyParcelable implements Parcelable {
private int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
private MyParcelable(Parcel in) {
mData = in.readInt();
}
}
You can also have a look here if you want other solutions.
I have a trick for you. Add Gson to your dependencies.
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.code.gson:gson:2.2.4'
}
Convert your object to Json and ship it as a String.
String data = new Gson().toJson(getMyData())
Convert it back from String in a new Activity
FindRouteOutputForDisplay data = new Gson(stringData, FindRouteOutputForDisplay.class).
You can make the class static and use it anywhere in your app.
you have passed wrong intent to start activity.
Intent newIntent = new Intent(FirstActivity.this, SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("value", data );
newIntent.putExtras(bundle);
startActivity(newIntent );
I also face this problem so I'm trying this below code:
Pass the object with intent
In starting activity we can set the parcelable object to an intent
User user = new User("1", "u", "u", "u");
ArrayList<User> userList = new ArrayList<User>();
Sensor sensor = new Sensor("1", "s", "s", true, user, userList);
intent.putExtra("com.score.senzors.pojos.Sensor", sensor);
In destination activity we can get the parcelable object from intent extras(bundle)
Bundle bundle = getIntent().getExtras();
Sensor sensor = bundle.getParcelable("com.score.senzors.pojos.Sensor")
Hope it Helps you

How do I save the Custom Spinner state

I extended android.widget.Spinner. and added an int field to my implementation. Now I want it to save the field value on orientation change. My first thought was using Bundle object for that:
override fun onSaveInstanceState(): Parcelable {
val bundle = Bundle()
bundle.putParcelable(SUPER_STATE, super.onSaveInstanceState())
bundle.putInt(PREV_ITEM, this.prevItem) // ... save stuff
return bundle
}
override fun onRestoreInstanceState(state: Parcelable?) {
val newState: Parcelable
if (state is Bundle) {
this.prevItem = state.getInt(PREV_ITEM) // ... load stuff
newState = state.getParcelable<Parcelable>(SUPER_STATE)
super.onRestoreInstanceState(newState)
}
super.onRestoreInstanceState(state)
}
But I get an error:
java.lang.ClassCastException: android.os.Bundle cannot be cast to android.widget.Spinner$SavedState
So I found Spinner source code and figured out that I have to extend inner static class SavedState and use it to save my field value. But I wasn't able to do that. Android Studio suggests that it "Cannot resolve symbol 'Saved State'".
So what do I do to save the state of my custom Spinner?
You cannot actually extend Spinner.SavedState because it created inside Spinner class. Even if you try to override Spinner.onSaveInstanceState you cannot implement this method in your custom class, because you don't have access to private variables of Spinner class.
What you can actually do is to create new class implementing Parcelable and use value returned from base class to construct your own class.
#Override
public Parcelable onSaveInstanceState() {
final MySavedState ss = new MySavedState(super.onSaveInstanceState());
ss.myInt = 100;
return ss;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
MySavedState ss = (MySavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
if(ss.myInt == 100) {
Log.d("TAG", "Success!");
}
}
static class MySavedState extends Spinner.BaseSavedState {
int myInt;
public MySavedState(Parcelable superState) {
super(superState);
}
public MySavedState(Parcel source) {
super(source);
myInt = source.readInt();
}
}

pass Object to another activity

I have found this way to do this
Student student = new Student (18,"Z r");
Intent i = new Intent(this, B.class);
i.putExtra("studentObject", student);
startActivity(i);
The problem is that if the object changed in the first activity No change took place in the another activity.
I thought how to make it like a constructor that no copy of the object is pass but the object it self.
Thanks
How about if you configure the "object" as a singleton of the entire application? This way, everybody (your app) sees the changes... See some insights here: http://developer.android.com/guide/faq/framework.html#3
For example, in some other file (Student.java):
public class Student {
public String Name;
}
Create a custom application class:
public MyApp extends Application {
private Student obj = new Student();
public Student getMyObject() {
return obj;
}
}
Anywhere in your application (e.g. SomeActivity.java):
Student appStudent = ((MyApp) getActivity().getApplicationContext()).getMyObject();
appStudent.Name = "New Name"; // "global" update
You could also look into a BroadcastReceiver. With a BroadcastReceiver you can send a message from one Activity to another and with an interface you can pass the object from one Activity to the other.
I think this is a great example, where a BroadcastReceiver is created to check the internet connection of the device. But you can easily convert this in a BroadcastReceiver with your own custom action to send the object.
Implement parcelable in your student class and you can copy the student into the intent.
How can I make my custom objects Parcelable?
Code works with parcelable classes
> Student student = new Student (18,"Zar E Ahmer"); Intent i = new
> Intent(this, B.class); i.putExtra("studentObject", student);
> startActivity(i);
Below is an example of bean class I use that implements parcelable. Here you would replace KmlMarkerOptions with Student
#SuppressLint("ParcelCreator")
public class KmlMarkerOptions implements Parcelable {
public MarkerOptions markeroptions = new MarkerOptions();
public String href = "";
public int hrefhash =-1;
public String id = "";
public long imageId = -1;
public int locationId = -1;
public int markerSize = -1;
public KmlMarkerOptions(){
}
public KmlMarkerOptions(Parcel in) {
this.markeroptions = in.readParcelable(null);
this.href = in.readString();
this.hrefhash = in.readInt();
this.id = in.readString();
this.imageId = in.readLong();
this.locationId = in.readInt();
this.markerSize = in.readInt();
}
#SuppressWarnings("rawtypes")
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public KmlSummary createFromParcel(Parcel in) {
return new KmlSummary(in);
}
public KmlSummary[] newArray(int size) {
return new KmlSummary[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(markeroptions, 0);
dest.writeString(href);
dest.writeInt(hrefhash);
dest.writeString(id);
dest.writeLong(imageId);
dest.writeInt(locationId);
dest.writeInt(markerSize);
}
}

How to pass Parcelable array to fragment and Activity

I'm working with custom parcelable class. I need to pass this class as array to another activity and new fragments. I googled, but I found arrayList but not arrays. Please mind that I need to pass arrays not Array lists. How to achieve that? Please mind again, performance is a big issue. So any solutions with less performance consumption is very welcome.
Any helps would be very appreciated.
You can pass your arrayList as below snipts.
TestFragment testFragment = new TestFragment();
Bundle args = new Bundle();
args.putSerializable("parsedData", (Serializable)mTestModelList);
testFragment.setArguments(args);
And Get these parcable data in Model as like below:
mTestModelList = (List<TestModel>)getArguments().get("parsedData");
YES, Serialisation is slow bit than Parcelable.
And you can implement that using parceler
Of course, the ParcelWrapper can be added to an Android Bundle to transfer from Activity to Activity using this:
Bundle bundle = new Bundle();
bundle.putParcelable("example", Parcels.wrap(example));
And dereferenced in the onCreate() method:
Example example = Parcels.unwrap(getIntent().getParcelableExtra("example"));
You can get more detail of performance related to Parcelable vs Serializable here.
Here is the write answer
// write parcelable array
final Bundle arguments = new Bundle();
MyParcelable[] myArray = new MyParcelable[10];
arguments.putParcelableArray("key"myArray);
// read parcelable array
MyParcelable[] myArray = (MyParcelable[])getArguments().getParcelableArray("key");
use like following class of your parcealble array
public class ParcelableLaptop implements Parcelable {
private Laptop laptop;
public Laptop getLaptop() {
return laptop;
}
public ParcelableLaptop(Laptop laptop) {
super();
this.laptop = laptop;
}
private ParcelableLaptop(Parcel in) {
laptop = new Laptop();
laptop.setId(in.readInt());
laptop.setBrand(in.readString());
laptop.setPrice(in.readDouble());
laptop.setImageBitmap((Bitmap) in.readParcelable(Bitmap.class
.getClassLoader()));
}
/*
* you can use hashCode() here.
*/
#Override
public int describeContents() {
return 0;
}
/*
* Actual object Serialization/flattening happens here. You need to
* individually Parcel each property of your object.
*/
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(laptop.getId());
parcel.writeString(laptop.getBrand());
parcel.writeDouble(laptop.getPrice());
parcel.writeParcelable(laptop.getImageBitmap(),
PARCELABLE_WRITE_RETURN_VALUE);
}
/*
* Parcelable interface must also have a static field called CREATOR,
* which is an object implementing the Parcelable.Creator interface.
* Used to un-marshal or de-serialize object from Parcel.
*/
public static final Parcelable.Creator<ParcelableLaptop> CREATOR =
new Parcelable.Creator<ParcelableLaptop>() {
public ParcelableLaptop createFromParcel(Parcel in) {
return new ParcelableLaptop(in);
}
public ParcelableLaptop[] newArray(int size) {
return new ParcelableLaptop[size];
}
};
}
now make Arraylist of ParcelableLaptop and put in the bUndle with argument
intent.putParcelableArrayListExtra("laptop", parcelableLaptopArray);
Where parcelableLaptop is your Arraylist of the Model. And to get the List:
Intent intent = getIntent();
ArrayList<ParcelableLaptop> parcelableLaptop = (ParcelableLaptop) intent
.getParcelableArrayListExtra("laptop");

Cannot put extra on an intent

I'm trying to put an object as extra on an intent. The class of the object was created by me, so I made it Parcelable.
public class NavigationDataSet implements Parcelable {
private ArrayList<Placemark> placemarks = new ArrayList<Placemark>();
private Placemark currentPlacemark;
private Placemark routePlacemark;
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
// TODO Auto-generated method stub
out.writeList(placemarks);
out.writeValue(currentPlacemark);
out.writeValue(routePlacemark);
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Parcelable.Creator<NavigationDataSet> CREATOR = new Parcelable.Creator<NavigationDataSet>() {
public NavigationDataSet createFromParcel(Parcel in) {
return new NavigationDataSet(in);
}
public NavigationDataSet[] newArray(int size) {
return new NavigationDataSet[size];
}
};
// example constructor that takes a Parcel and gives you an object populated with it's values
private NavigationDataSet(Parcel in) {
in.readTypedList(placemarks, Placemark.CREATOR);
this.currentPlacemark = in.readParcelable((ClassLoader) Placemark.CREATOR);
this.routePlacemark = in.readParcelable(Placemark.class.getClassLoader());
}
}
In the Activity, I declared the variable like this:
private List<NavigationDataSet> ds;
And the intent creation:
public static Intent mapIntent(Context context){
Intent i = new Intent(context, mapsView.class);
i.putExtra("NavSet", ds);
return i;
}
The variable ds is initialized on an AsyncTask that is executed on the onCreate method.
And I got a precompiling error on the putExtra instruction:
Cannot make a static reference to the non-static field ds
But here http://developer.android.com/reference/android/content/Intent.html it doesn't say it has to be a static variable.
And if I change it to static, the it says:
The method putExtra(String, boolean) in the type Intent is not
applicable for the arguments (String, List)
But I'm not passing a boolean, it's a Parcelable!!! So what do I do? I really don't understand the way this is working.
ArrayList<ParcelableObject> pointsExtra = new ArrayList<ParcelableObject>();
intent.putExtra("", pointsExtra);
http://developer.android.com/reference/android/content/Intent.html#putParcelableArrayListExtra%28java.lang.String
In your case, ds is not a static variable, therefore you can't reference it in a static method. Either make ds static, pass is as an argument to your mapIntent function, or make your mapIntent function not static.

Categories