Android has recently introduced WorkManager for scheduling tasks. One of the powerful feature of this WorkManager is chaining multiple tasks through combine, then and beginWith operators. Data class is being used to send data between these tasks. But After going through the Data and Data.Builder class, I haven't found the way to send Class object through Data class between different tasks, not even through Serializable or Parcelable.
How can I send class object between different tasks?
The Data is a lightweight container which is a simple key-value map and can only hold values of primitive & Strings along with their String version. It is really meant for light, intermediate transfer of data. It shouldn't be use for and is not capable of holding Serializable or Parcelable objects.
Do note, the size of data is limited to 10KB when serialized.
I asked the same question here
#Sagar does point out the correct answer to your question, just posting my answer here for people looking for potential work arounds.
Related
I'm trying to pass large data from one activity to another. For business reasons, I cannot save this data to persistent storage and need it to stay in memory.
Up until now, I've been using Intents to pass Serializable data, but with larger data, I've been receiving TranstactionTooLarge exceptions/crashes.
What are my options? I am using Kotlin, so Kotlin-specific solutions are welcome.
I've thought of using Singletons, but I'm unsure of the side effects of that, or if there is a better solution.
You can use singleton object and store your data in it. In intent you can pass some key (Int or maybe String) to get your data from singleton in receiver activity.
Also there are implementations of event bus pattern, that are applicable for same reason.
TransactionTooLargeexception reflects limitations of IPC mechanism on Android, in the way, how data are transfered between processes.
Since you are sharing data between activities, given restrictions you have, following possibilities came to my mind:
keeping data in a singleton instance of repository (which takes reponsibility for reloading of data in case, they get lost during recreating of activities etc.) and trafering just unique indetifier(or identifiers)
reduce size of data by simple data transformation or compression(integer instead of float, long for Date etc.)
as pointed out by #nsk, with an event bus you can overcome limitations of IPC, but this brings a "fun" with activity's lifecycle
kotlin brings kotlinx.serialization into the game, not much experience on my side, but sure something you can evaluate(performance and data size)
Independently of selected solution to your problem, I would recomend to use Parcelable instead of Seriazable for Intent, mainly for performance reasons, reflection is still an issue and I can barely remember having lint warnings. For Parcelable with Kotlin there is indeed a handy solutionwith Parcelize annotation provided by Kotlin Android Extensions library.
Simple object looks like this
#Parcelize
class Student(val name: String, val year: Int) : Parcelable
I want to know exact ,
whether should I used parcelable or serialization technique
for sending data from one activity to other?
is it compulsory to
use one of them for sending data from one to other?
when should I use them?
and the exact difference between them and performance
of both of them in java aspects.
Thanks in advance.
public class GetSetClass implements Serializable {
private int dt = 10;
/** pass any object, drwabale */
public int getDt() {
return dt;
}
public void setDt(int dt) {
this.dt = dt;
}
}
These concepts are related to Inter Process Communication (IPC).
When sending data between two applications, we have to make sure that both applications should understand the format of the data that is being sent.
Especially when you are sending non primitive data type values like classes and objects between two applications, We have to convert them into Operating System understandable format. O.S understands only primitive types (ints, chars etc). The reason for conversion is we have to O.S communication channel to transmit the data.
This process of converting Non primitive types to primitives and sending across to other application over some communication channel is called as Serialization. The reverse process is called as De Serialization.
In Java, IPC depends heavily on Serializables for serialization. But serialization is designed by keep desktop applications in mind. When you are doing IPC in mobile applications we have to make sure that the process of IPC is not too heavy.
In simple terms serialization is a heavy concept for IPC.
So in place of Serialization Android opted for Binders for achieving light weight Inter process communication. Binders internally depends heavily on parcels, to do the IPC.
Parcels are light weight serializables. It is preferred to use parcels for marshaling objects into byte streams.
Note: Binder IPC heavily depends on Shared memory concept to make sure that there is not much data duplication while sharing between applications.
whether should i used parcelable or serialization technique for sending data from one activity to other.
If you are sending a non-primitive type data/Object to another activity through the intent you have to either Serialize or implement Parcelable for that object. The preferred technique is Parcelable since it doesn't impact the performance.
is it compulsory to use one of them for sending data from one to other. / when should i use them.
It is only compulsory/used for sending non-primitive type data objects.
and the exact difference between them and performance of both of them in java aspects.
Serialization does impact the performance. For more details check this link Android Parcelable and Serializable
Got a very good explanation of difference between Parcelable and Serialization.
To start with your question though its been a long time, it may help others:
whether should I used parcelable or serialization technique for sending data from one activity to other?
Ans: Parcelable is best choice (why explained later).
is it compulsory to use one of them for sending data from one to other?
Ans: Yes, as sending data (object) from one to other requires streams of bytes to be written and retrieved and that can be done either through parcelable or serialization.
when should I use them?
Ans: This part you arleady answered i.e, passing data from one activity to another.
and the exact difference between them and performance of both of them in java aspects.
Ans: 1. Parcelable is well documented in the Android SDK; serialization on the other hand is available in Java.
In Parcelable, developers write custom code for marshaling and unmarshaling so it creates less garbage objects in comparison to Serialization. The performance of Parcelable over Serialization dramatically improves (around two times faster), because of this custom implementation.
Serialization is a marker interface, which implies the user cannot marshal the data according to their requirements. In Serialization, a marshaling operation is performed on a Java Virtual Machine (JVM) using the Java reflection API. This helps identify the Java objects member and behavior, but also ends up creating a lot of garbage objects. Due to this, the Serialization process is slow in comparison to Parcelable.
Answer taken from:
this link
See also:serialization explained
Java Serializable:-
Serializable comes from standard Java and is much easier to implement all you need to do is implement the Serializable interface and add override two methods.
The problem with Serializable is that it tries to appropriately handle everything under the sun and uses a lot reflection to make determine the types that are being serialized. So it becomes a beefy Object.
Androids Parcelable:-
Android Inter-Process Communication (AIPC) file to tell Android how is should marshal and unmarshal your object.It is less generic and doesn't use reflection so it should have much less overhead and be a lot faster.
Read More from http://www.3pillarglobal.com/blog/parcelable-vs-java-serialization-android-app-development
both parceling and serializing are ways to marshall and unmarshal data. in android this is used to pass non-primitive data types between components and processes. in general, android allows either serializable or parcelable objects, so you can choose your method. the exception to that is with AIDL interfaces. objects must be parcelable to be passed / returned.
serialization uses reflection to automatically marshall and unmarshal data. in most cases implementing the marker interface is enough to make it just work. with parceling, you have to write the code to marshall and unmarshal the data yourself.
and hence, that is why parceling is faster. the object does not need to be reflected to discover the fields. it's the reflection that makes it slow.
serialization also has in-built versioning ... if you try to unmarshal to a different version of the object's class that was marshalled, the process will fail in a predictable way. with parceling, you can do the same thing but you need to implement it yourself by adding a "version field to your object, and code that checks the version when unmarhsaling.
that being said, i typically use serialization. with simple objects you won't notice the difference. you can always change to use parceling later in development if you discover performance issues.
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).
My Activity starts an IntentService that then calls a remote API. I then need to pass the resulting data back to the Activity (through a BroadcastReceiver). Within much of the rest of the app this data is encapsulated in a single class, with primitive member variables holding the data. But as the results are passed across through an Intent I'm limited in my options as I can't pass a standard Java object across the boundary. I am looking for a neat and tidy way to pass objects like this through an Intent, without requiring large amounts of repetitive code needing to be written.
Options:
Implement Parcelable on my class. Tedious to implement/maintain
Pass each member variable individually, and reconstruct the object on the other side. Tedious to implement/maintain
Use AIDL to specify the contract. Never done it before, not sure how appropriate this is.
Serialise the object and pass the String through to the Activity. Is there a String length limit for passing through an Intent? I gather there can be performance issues.
Which approach should I use, and why?
Does this remote API serialize the data in some way (JSON or XML)? Can you not hold off on the deserializing until it reaches the Activity?
Failing this I would see serialization as the best option. Parcelable is a specific type of serialization which, as you point out is a little more tricky to implementent but should be more performant if you are concerned about performance. Unless you are handling a huge amount of traffic, though, the serialization option shouldn't be too sluggish in my experience.
This is a question I've now had for a few different apps I've built, and I have yet to be satisified with any of the solutions I've come up with. I thought I'd put it out there to the community to see other solutions there might be.
Let's say you have an Activity that downloads a complex tree of data (in this case via json, but it could be anything), unmarshalls that data to a set of java objects (in this case using gson, but again, could be whatever), then spawns additional activities to view different parts of that data. There might be one activity to view Trips in your response, and another to view Flights in those trips, and maybe another to view Passengers of those flights.
My initial implementation of this app was to unmarshall all the Trips in the first activity, then pass them by value (as an extra in the intent) to the TripActivity. The TripActivity then passes individual flights to the FlightActivity, and so on.
The problem with this is that there's a noticeable pause between activities while the app serializes and deserializes the data. We're talking several seconds. The pause is quite noticeable when my tree uses Serialization or Parcelable to pass data around. Initial performance testing with using google's Parcelable instead show a roughly 30% speedup over serialization, but Parcelable is difficult to work with and doesn't seem to handle circular object references well like Serialization does, and besides it still pauses for almost as many seconds, so I've put that experiment on the backburner while I try other things.
So then I tried moving the tree of objects directly into the Application class. Each activity just gets the tree directly from the app whenever it needs it. This makes performance quite snappy, but handling corner cases like unexpected activity start/stops (either due to activity crashes or because the activity has been closed temporarily to make more memory available, or whatever other cause) seems tricky. Perhaps it's no more than implementing onSaveInstanceState(), I'm not sure, but the solution seems a bit hacky so I haven't investigated further yet.
So in search of a less cobbled-together solution, I tried creating a custom ContentProvider to store and retrieve my objects. Since ContentProviders can be configured to run in-process using multiprocess=true, I thought that would be an excellent way to avoid serialization costs while doing something more "standard" than storing data in the Application object. However, ContentProviders were clearly not intended to return arbitrary object types -- they only support types such as numbers, strings, booleans, etc. It appears I can finagle one to store arbitrary objects by using ContentResolver.getContentProviderClient().getLocalContentProvider() and accessing my custom class directly, but I'm not sure that's less hacky than storing data in the Application object.
Surely someone must have a good solution to this problem. What am I doing wrong?
In addition to fiXedd's solution, another one is to use a local service. Have the service "own" the objects, with activities calling service APIs to get whatever it needs. The service can also be responsible for fetching and parsing the data, encapsulating that bit of logic.
The Application object is the "red-headed step-child" of Android components. Members of the core Android team have come out against the practice of creating custom Application subclasses, though it is certainly supported by the API. Having engineered one ADC2 200 application that leveraged a custom Application subclass, I can say that I should have gone with a service in my case as well. Live and learn...
By using the local binding pattern, your service will automatically be created and destroyed as needed, so you don't have to worry about that. And, by definition, a local service runs in the same process/VM as your activities, so you don't have to worry about marshaling overhead like you would in the ContentProvider scenario.
The way I'm handling this in one of my apps is downloading the data then shoving it into a database. This way I don't have to carry all those objects around (which, IIRC, eat about 1kb each just for the object instantiation) and I can easily pull just the data that I need. I don't know if this will work for you, but it worked for my use-case.
Another approach would be to save the data objects to a shared preferences file. That's how we implemented one of our apps, but I didn't like that approach because it seems too slow.
It's bad coding practice, but the fastest way may be to just use a service to parse the data and save the data to a static class that you can use for the rest of the app's life.