I'd like to pass a custom Object from one activity to another, the Object consists of a String and a List of another custom Object which consists of an array of strings and an array of ints. I've read https://stackoverflow.com/a/2141166/830104, but then I've found this answer https://stackoverflow.com/a/7842273/830104. Which is better to use Bundle or Parcelable? What is the difference? When should I use this each? Thanks for your replies, Dan
Parcelable and Bundle are not exclusive concepts; you can even deploy both on your app at a time.
[1] Term Parcelable comes with Serialization concept in Java (and other high-level language such as C#, Python,...). It ensures that an object - which remains in RAM store - of such Parcelable class can be saved in file stream such as text or memory (offline status) then can be reconstructed to be used in program at runtime (online status).
In an Android application, within 2 independent activities (exclusively running - one starts then other will have to stop):
There will be NO pointer from current activity to refer to previous one and its members - because previous activity is stopped and cleared out form memory; so that to maintain object's value passed to next activity (called from Intent) the object need to be parcelable (serializable).
[2] While Bundle is normally the Android concept, denotes that a variable or group of variables. If look into lower level, it can be considered as HashMap with key-value pairs.
Conclusion:
Bundle is to store many objects with related keys, it can save any object in native types, but it doesn't know how to save a complex object (which contains an ArrayList for example)
Parcelable class is to ensure a complex instance of it can be serialized and de-serialized during runtime. This object can contains complex types such as ArrayList, HashMap, array, or struct,...
[UPDATED] - Example:
//Class without implementing Parcelable will cause error
//if passing though activities via Intent
public class NoneParcelable
{
private ArrayList<String> nameList = new ArrayList<String>();
public NoneParcelable()
{
nameList.add("abc");
nameList.add("xyz");
}
}
//Parcelable Class's objects can be exchanged
public class GoodParcelable implements Parcelable
{
private ArrayList<String> nameList = new ArrayList<String>();
public GoodParcelable()
{
nameList.add("Can");
nameList.add("be parsed");
}
#Override
public int describeContents()
{
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags)
{
// Serialize ArrayList name here
}
}
In source activity:
NoneParcelable nonePcl = new NoneParcelable();
GoodParcelable goodPcl = new GoodParcelable();
int count = 100;
Intent i = new Intent(...);
i.putExtra("NONE_P",nonePcl);
i.putExtra("GOOD_P",goodPcl);
i.putExtra("COUNT", count);
In destination activity:
Intent i = getIntent();
//this is BAD:
NoneParcelable nP = (NoneParcelable)i.getExtra("NONE_P"); //BAD code
//these are OK:
int count = (int)i.getExtra("COUNT");//OK
GoodParcelable myParcelableObject=(GoodParcelable)i.getParcelableExtra("GOOD_P");// OK
Related
Lets say I have a Product object that has a pricetag property. I also have a List of Stores, each with its own list of Products.
Specifically, Product p has price $9.99, and a Store s which is in the Store list had p in its product list.
I have this store List in an android activity, and I pass Product p to another activity through an intent, and then change that object's price in the new Activity. Once I finish this new Activity and return to the old one, are the changes made to that object reflected in Store s's product list?
No the references are not maintained. A parcel is:
Container for a message (data and object references) that can
be sent through an IBinder. A Parcel can contain both flattened data
that will be unflattened on the other side of the IPC (using the various
methods here for writing specific types, or the general
Parcelable interface), and references to live IBinder
objects that will result in the other side receiving a proxy IBinder
connected with the original IBinder in the Parcel.
If you look at any parcelable, there is a CREATOR. That creates a new object out of the Parcel.
For example:
public static final Creator<Employee> CREATOR = new Creator<Employee>() {
#Override
public Employee createFromParcel(Parcel in) {
return new Employee(in);
}
#Override
public Employee[] newArray(int size) {
return new Employee[size];
}
};
So you if want any data back from another activity, use startActivityForResult as Lawrance mentioned.
Is it a good idea to pass a list of object from one Activity to another for Android ?
It is quiet troublesome to pass a list of object in an intent, and I wonder whether it affect the performance if the object list is too large or the object is too complicated.
Is it a better solution to get the list of object from other place, for example, query the DB once more , or save the list of object in a temporary class and fetch it in new Activity?
As long as you are passing Parcelable objects' list, nothing's wrong when passing through Intent. Regarding performance, that is up to you and the amount of data you pass.
As per my experience, If you are passing data up to 1MB of size, it should be fine. Anything above that will fail as this seems to be the limit. Read this.
Besides, you are welcome to use preferences, SQLite, files or static-object-referencing methodologies to fetch your data anytime and anywhere.
Solution1 : Use Intent
Send :
Intent data = new Intent(Activity1.this,Activity2.class);
data.putParcelableArrayListExtra(Constant.LIST_OBJECT,
(ArrayList<? extends Parcelable>) getObjects());
receive :
List<YOUR_OBJECT> objects = data.getParcelableArrayListExtra(Constant.LIST_OBJECT);
Solution2 :
public class SessionData {
private static SessionData instance;
private final List< YOUR_OBJECT > listSessionObjects;
private SessionData() {
listSessionObjects = new ArrayList<>();
}
public static final SessionData getInstance() {
if (instance == null) {
instance = new SessionData();
}
return instance;
}
public List<YOUR_OBJECT> getListSessionObjects() {
return listSessionObjects;
}
public void setListSessionObjects(List<YOUR_OBJECT > objects) {
listSessionObjects = objects
}
}
to use it :
SessionData.getInstance().getListSessionObjects();
SessionData.getInstance(). setListSessionObjects(objects);
i have a POJO object defined like this:
public class MYPOJO implements Serializable {
int myint;
String mystring;
}
then when im passing the info to an activity i do this:
Intent i = new Intent(this, WearActivity.class);
Bundle b = new Bundle();
MYPojo pojo = new MYPojo();
pojo.mystring="cool";
b.putSerializable("someString", pojo.mystring);//this line is my issue
i.putExtra("coolBundle",b);
startActivityForResult(i, 0);
and to read the 'someString' extra i do:
Bundle b2 = getIntent().getBundleExtra("coolBundle");
b2.getString("someString");
So now onto my question: is there really any difference if i do the following if if at the end im still calling for retrieval b2.getString("someString") :
b.putString("someString",pojo.mystring)
vs
b.putSerializable("someString",pojo.mystring) ?
In practice, there isn't a difference you'll see between passing a string, or passing a serializable string between activities, besides "efficiency" or possible usage of reflection/security. It might be more of a design and principle issue I have with passing a String in as "serializable". Essentially by passing in a String as Serializable, Android/Java will utilize the wrapper of String, which contains a data structure of char[] behind the scenes.
TLDR; If your POJO contained more data, I would highly recommend implementing Parcelable. More information can be found in this SO answer here. But if you are going to be passing just a String, I would use the putString/getString methods that Android provides for us.
I have a problem with with sharing data between two different activities. I have data like :
int number
String name
int number_2
int time
int total
I'm trying to make something like order list with this set of data . So it will take one set of data , then back to previous activity , move forward and again add data to it .
I have an idea of making it in array of object - but data inside was cleared after changing activity.
How can I make it ?
I don't know if and how to add Array of object to SharedPreferences , and get value of one element from there.
You should have a look at the documentation of the Intent(s) if you want to do that on the fly associating a key to the value(s) that you want to pass to your second activity.
Anyway, you can think any(sharedpref, database,...) way to pass your parameters but for those kind of things it's a convention and a good practice to follow that.
Don't used share preferences for this...Use the singleton pattern, extend Application, or just make a class with static variables and update them...
You can use .putExtra but since you are communicating with more than one activity the above suggestions are probably the best.
public class ShareData {
private String s;
private int s;
private static ShareData shareData = new ShareData();
private ShareData(){}
public static ShareData getInstance(){ return shareData}
//create getters and setters;
}
Why not to use Intents
Intent intent = new Intent(FirstActivity.this, (destination activity)SecondActivity.class);
intent.putExtra("some_key", value);
intent.putExtra("some_other_key", "a value");
startActivity(intent);
in the second activity
Bundle bundle = getIntent().getExtras();
int value = bundle.getInt("some_key");
String value2 = bundle.getString("some_other_key");
EDIT if you want to read more about adding array to shared preferences check this
Is it possible to add an array or object to SharedPreferences on Android
also this
http://www.sherif.mobi/2012/05/string-arrays-and-object-arrays-in.html
How can I put an array of arrayList into a Bundle?
ArrayList < myObjects >[] mElements;
Make YourObject implement the Parcelable interface, then use bundle.putParcelableArraylist(theParcelableArraylist).
Edit: whoops misread the question. Why do you want to save an array of arraylist? If its for persisting in an orientation change, maybe you want to use onRetainNonConfigurationInstance instead?
Edit 2: Ok, here goes. Create a new Wrapper class that implements Parcelable (note that myObjects also have to be parcelable). The writeToParcel method will look something like this:
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mElements.length);
for(ArrayList<MyObject> element : mElements) {
dest.writeParcelableArray(element.toArray(new MyObject[0]), flags);
}
}
And the constructor:
private Wrapper(Parcel in) {
int length = in.readInt();
//Declare list
for (int i = 0; i < length; i++) {
MyObject[] read = in.readParcelableArray(Wrapper.class.getClassLoader());
//add to list
}
}
Not possible using bundle, as bundle allows arraylist of primitives only...
Try to use parcleable or application level data or static variable (bad practice).
If your objects support serialization, marked with the Serializable interface, then you should be able to use bundle.putSerializable.
ArrayList supports Serializable , but I'm not sure about a plain array.
I just use putSerializable(myarraylistofstuff) and then I get back with a cast using get(), you just need to silence the unchecked warning. I suspect (correct me if wrong) you can pass any object faking it as Serializable, as long you stay in the same process it will pass the object reference. This approach obviously does not work when passing data to another application.
EDIT: Currently android passes the reference only between fragment, I've tried to pass an arbitrary object to an Activity, it worked but the object was different, same test using arguments of Fragment showed same Object instead.
Anyway it deserializes and serializes fine my Object, if you have a lot of objects it's better to use Parcel instead