I'm a C/C++ guy, and I'm quite new to Java and Android.
So I'm creating a class instance in Activity "A" and I'm trying to use this instance to Activity "B". In C/C++ you would simply pass the address (pointer) of the instance.
Now I learned that with Android I should use a Parcel, but I don't get the idea: why would I want do all that parceling/deparceling procedure when all I want to do is passing a pointer?
Please enlighten me!
This is related to the Android activity model.
Since your app may be killed by the system to recover RAM (this should only happen when it's in the background, unless the system is in a really bad situation), an object reference just won't do. It'd be completely worthless once your process dies.
The intent you use to start activities is saved by the Activity Manager, so that it can be used to recreate your activity when the user navigates back to it. That's why all the data in your intent has to be parceled.
Keep in mind that this means that your two activities will have two similar instances -- but naturally, they will not be the same object, so changes to one won't be reflected in the other.
Parcel or parcalable is an efficient and alternative way to serialize objects in Android. Its an alternative to Serialization in core Java.
Java Serialization API allows us to convert an Object to stream that we can send over the network or save it as file or store in DB for later usage.
Its a way to exchange objects between sender and receiver(Class). Receiver than deserializes this object.
In Android parcel is used to exchange objects between different activities by using Intents.
java doesn't work like c/c++, you don't work directly with the memory. If you want to pass an object from A to B, you have to set it in a Bundle, and add that bundle to the intent. if it's a custom class, let's call it C, C should implement parcellable. Java works by value, not by reference.
custom parcelable objects
how do i pass data between activities?
Related
Why does Android use parcels to pass data between components (e.g. two Activities)? Why not just a reference to the object?
Parcel is a container for a message(data and object references). In transmission, Parcel contains a byte stream version of a chosen Java Object that contains information about it's attributes. Such data is written to Parcel at sending component, and is read at receiving component. Because the protocol is also designed to support IPC(Inter-Process Communication), only a reference wouldn't suffice. If you really want to use just a reference you can declare your object containing data public static, although I wouldn't recommend this because of the global scope & tight coupling of components.
If we look at common ways of sharing data between activities, we can make a reasonable guess at why this is the case.
Alternatives include using singletons and SharedPreferences - entities that basically act as "owners" of the state stored by the data. The use of a third party keeps the activities decoupled, as compared to activities simply giving each other references.
We want activities to be decoupled since any two activities should be fairly distinct entities, with possibly independent lifecycles. This is why if we can simply pass information by value (rather than keep a live reference dependency), we should. This is also why it's comparable to Inter-Process Communication, which works around the lack of shared memory.
I would like to ask about calling an Activity with arguments. I have seen many examples about it. But I would like to ask an explanation why it is somehow "not easy" or "not simple" to create(call) an activity with custom arguments.
I've seen many posts like this and others. People passing strings but not custom objects. Yes, they are passing custom objects by implementing serializable and parceable methods but that doesn't seem efficient (I might be wrong because haven't seen it). For final declared classes, it is even more work to do.
When we pass String with putExtras(String name, String value), why is a function like putExtras(String name, Object object) not defined? wouldn't it be easier to pass any custom objects by that?
And about the complexity of the process, an explanation was given in the post here
beacuse apps are in different processes, and have separate memory
address spaces, you cant just send pointer (reference) to memory block
in your process and expect it to be available in another process.
But, still, I couldn't find a reason that satisfy me or helps me to realize what I am not seeing. Okay, let's say apps are in different processes and their memory spaces are different. So are we copying the data to be passed into another activity's memory space? or at least, shouldn't the activities which belong to same application (I believe activities in an app has something common that addresses to its app) have the common memory space so that they could easily share or pass data?
I am just trying to clarify myself about this. I know Android should not be compared with Windows development but feels like it could be better if things were simpler. I know I am missing something about this, otherwise everyone knows simpler would be better. But what is the thing that prevents passing things easier?
Thanks.
why is a function like putExtras(String name, Object object) not defined? wouldn't it be easier to pass any custom objects by that?
Because startActivity() always crosses a process boundary, and therefore whatever gets passed needs to be convertible into a byte array for transport.
So are we copying the data to be passed into another activity's memory space?
We are copying data between processes.
or at least, shouldn't the activities which belong to same application (I believe activities in an app has something common that addresses to its app) have the common memory space so that they could easily share or pass data?
Except that the primary work of startActivity() is not done by your application process, but rather by a core operating system process.
I know Android should not be compared with Windows development but feels like it could be better if things were simpler.
A better analogy is Web development, where you do not pass objects between client and server, but rather data marshalled to/from strings or byte arrays.
Just as you have figured out yourself you pass data between activities through a Bundle, like this:
Intent intent = new Intent(context, MyActivity.class);
intent.putExtra(key, "some string");
intent.putExtra(key, true);
intent.putExtra(key, 1.5f);
The thing is that Intents and Bundles are a very versatile way of passing data not only between your own activities, but also to other applications, say by launching a messaging client and providing a predefined subject and body. This is very powerful but it is also a constraint. What if you like to pass MyFooClass? Well you can't do that since an Intent is an abstract way of performing an operation, not only within your own application. One might argue that Google should have made an exception for intents between your own activities, but I really don't see this as a very big problem.
You can, as you say yourself, serialize an object using serializable interface, but you could also serialize it as a JSON object. I would also say that if you need to pass complex data structures between activities you really need to rethink your design. You should probably have some global application state (in your Application or similar class) and only pass ids, keys or similar that you can use to look up the data from your application state.
I have 2 activities and I'm trying to send from Activity A to Activity B some huge objects that implements Serializable. The problem is the time taken by Android OS to serializate this objets. Is there any way to send parameters between Activities? I tryed sending to Application object and getting it in the next activity but I think this way is dirty...
This is exactly why Android created Parcelable, since it can outperform Serializable in this use case.
Android Parcelable and Serializable
http://shri.blog.kraya.co.uk/2010/04/26/android-parcel-data-to-pass-between-activities-using-parcelable-classes/
Here are some alternate ideas you could use instead of passing huge amount of data by Serializable or Parcelable:
If you use this big chunk of data often you might consider using a Service. It would hold the data, process it and deliver when needed. Afterwards it can be terminated.
Another approach would be to put a reference to this big object in Application object (like this). "Global reference" doesn't usually sound good, but this is recommended in some cases. Even further, if you still find it "dirty" you can use WeakReference and get rid of it as soon as it's passed to second Activity and used by it.
Or, yet another way, you could consider doing all the work in singular Activity (without starting the second one) and just play with Views. If it's possible for you of course.
Just wondering what is a better practice to pass information between activites, adding it to a bundle or using a singleton class to store and access this data. I have used both in the past for various android side projects, but I am now working on an android project that is of much larger scale, so would prefer to do things right towards the beginning.
My application authenticates users and then will have to do various queries based on it's id. To minimize coupling between activities, I would think just adding the id to the bundle, and then letting each activity query for the information that it needs, would be the best bet; however to increase responsiveness, I was leaning towards using a singleton class to store persistent information, preventing more queries than need be.
Personally, I would create an extension of Application to store the state of your app and share data between the different activities. The Application acts as the context for your whole app and Android guarantees there will always only be one instance across your app. Hence it works similar to defining your own Singleton, but using Application will allow Android to take control of the life cycle of your shared data and basically do the memory management for you.
Here are some more details. If you go down this path, you can simply add any getter/setter (or other) method to your application extension to store/retrieve data and do operations on it. Especially the latter can become quite a pain to manage (and keep consistent) when using Bundles passed back and forth between activities. If would only use a Bundle if the data is needed in just one or two places that are neighbours in the activity flow and does not need any (complex) operations to be run on it.
The better way to go for you is to use SharedPreferences to keep userId you need to keep and reuse. Of course you can use singleton approach or even Application class, but the data will be lost after application is killed.
The only time I pass data between Activities via bunlde is if it's something that I won't need to access for a while(i.e the the resID of a resource I want to use only once in the calling activity, etc). I would also think the difference in responsiveness would be very minimal, so that shouldn't be of concern. I suggest the singleton approach
Passing bundles is a tedious job. You'll have to pass a bundle for every change in activity to make sure that the value is not lost, even if you're not using the value in the called activity.
Singleton pattern have some bad results. For example:From Main activity you call secondary activity. Phone call interrupted your work.After ending phone call Android is trying to bring secondary activity to screen. Here is my nightmare - many users complaint about exceptions - Google reported to me NULL pointers in my singleton. So you have to provide not only singleton, but all data inside singleton have to be as singleton too. This maked come very complicated :(
I know this question has been asked multiple number of times and i have been through a lot of these questions......almost all of these questions throw up the use of the parcelable interface for your class.
However in a couple of questions i came across a quotation:
"NOTE: Seeing Parcelable might have triggered the question, why is Android not using the
built-in Java serialization mechanism? It turns out that the Android team came to the conclusion
that the serialization in Java is far too slow to satisfy Android’s interprocess-communication
requirements. So the team built the Parcelable solution. The Parcelable approach requires
that you explicitly serialize the members of your class, but in the end, you get a much faster
serialization of your objects.
Also realize that Android provides two mechanisms that allow you to pass data to another
process. The first is to pass a bundle to an activity using an intent, and the second is to pass a
Parcelable to a service. These two mechanisms are not interchangeable and should not be
confused. That is, the Parcelable is not meant to be passed to an activity. If you want to start
an activity and pass it some data, use a bundle. Parcelable is meant to be used only as part of
an AIDL definition."
This quote can also be found in the book Pro Android 2.
Now seeing that all activities within the same application run in the same process(Every Activity in Android is a Process,or One Application is one process),unless otherwise specified in the manifest,communication within the activities of the same application is not Interprocess communication per se.So is it really faster to use the parcelable class or is it just enough to pass your object attributes through bundle via intent ?
Shedding any light on this aspect will be largely appreciated.
Cheers !!
There's a FAQ for that. :)
The short answer is that the Android team recommends three techniques for passing data between activities and services within an app: a singleton class; a public static field or method; a HashMap of WeakReferences to Objects (and you pass the key in the intent). The major issue to keep in mind is how your data is going to behave under various lifecycle events. (For instance, if the user turns the phone, by default your activities will be destroyed and recreated; your data handling method needs to be designed with that in mind.)
The Parcelable construct is designed to be very fast at passing data across application memory boundaries: within an application you are MUCH better served using Bundle because all the memory locations the data is stored in are accessible to both the sender and the receiver. Since the in-memory objects are accessible there is no need to incur the cost of reconstruction: just use the Bundle, which is really just a glorified HashMap with type-specific put/get methods.
For AIDL and IPC purposes you can't (by default) share memory locations so you need an efficient way of moving data: this is where Parcelable kicks in. Unless one of the components of your application is using the remote process capability then there is no need to use Parcelable.
From docs:
Parcelables
The Parcelable protocol provides an extremely efficient (but
low-level) protocol for objects to write and read themselves from
Parcels. You can use the direct methods writeParcelable(Parcelable,
int) and readParcelable(ClassLoader) or writeParcelableArray(T[], int)
and readParcelableArray(ClassLoader) to write or read. These methods
write both the class type and its data to the Parcel, allowing that
class to be reconstructed from the appropriate class loader when later
reading.
There are also some methods that provide a more efficient way to work
with Parcelables: writeTypedArray(T[], int), writeTypedList(List),
readTypedArray(T[], Parcelable.Creator) and readTypedList(List,
Parcelable.Creator). These methods do not write the class information
of the original object: instead, the caller of the read function must
know what type to expect and pass in the appropriate
Parcelable.Creator instead to properly construct the new object and
read its data. (To more efficient write and read a single Parceable
object, you can directly call Parcelable.writeToParcel and
Parcelable.Creator.createFromParcel yourself.)
Bundles
A special type-safe container, called Bundle, is available for
key/value maps of heterogeneous values. This has many optimizations
for improved performance when reading and writing data, and its
type-safe API avoids difficult to debug type errors when finally
marshalling the data contents into a Parcel. The methods to use are
writeBundle(Bundle), readBundle(), and readBundle(ClassLoader).