I would like to transmit an Android Object over a Socket with low overhead.
Should I use standard java.io.Serializable or android.os.Parcel?
Thank you!
Neither.
Parcel is designed for IPC, and other uses are albeit arguably efficient, dangerous. The documentation says
Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.
This also means that you need to be sure that the remote side has got the exact same version of Android and of your code to be sure it will work.
Serializable has similar problems, and in the (android) dcumentation there is even a hint towards the solution:
Warning: this interface limits how its implementing classes can change in the future. By implementing Serializable you expose your flexible in-memory implementation details as a rigid binary representation. Simple code changes--like renaming private fields--are not safe when the changed class is serializable.
[...]
Recommended Alternatives: JSON is concise, human-readable and efficient. Android includes both a streaming API and a tree API to read and write JSON. Use a binding library like GSON to read and write Java objects directly.
If you want to move data from one device to another, I think you are better off creating a protocol for the data, ship it over, and populate the remote objects with that data. JSON is probably a good place to start.
Good luck!
If your message is longer, more complex or otherwise you need more efficiency, I would recommend to try use Google Protocol Buffers. They would allow some reasonable amount of alterations like adding new fields, or removing previously optional fields, or adding a completely new structure as a field. However you will also have the real classes with the real setters and getters (can be immutable versions or mutable builders, how do you prefer). Stricter control over that do you put is not as bad thing as may appear.
think XML, but smaller, faster, and simpler
The major drawback of serialized objects is not that you cannot alter the protocol details later. Differently, you can do many compatible changes if you introduce versions numbers and you cannot rename the property name in JSON either if you want legacy client to find that property.
However serialized objects are Java specific and you cannot have a more efficient C++ server client or use Python for prototyping, for instance, if you decide in the future. Protocol buffers are language neutral.
Transmitting an object through a socket depends a lot on what will be receiving the object. Usually such a transfer relies on a text-based serialisation such as XML or JSON.
First, define an object to send. As an example, we can define a class called Message to encapsulate our communications:
public class Message implements Serializable {
private static final long serialVersionUID = 1L; // Your version number
private int senderID;
private String messageText;
public Message(int id, String text) {
senderID = id;
messageText = text;
}
public String getText() {
return messageText;
}
}
Next, instantiate the object, wrap the socket's streams in object streams, then send the message across the socket:
Message sayhey = new Message("123456789", "Hello");
Socket socket = new Socket(host, port);
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(sayhey);
On the other side of the socket, the message can be retrieved and used by invoking methods on the returned object:
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Message messageObject = (Message) in.readObject();
String messageText = messageObject.getText();
you can implement Serializable.
Related
I'm a bit confused, as from a long time i am saving the json response directly to an ArrayList> and displaying to my listView, but now, looking on other people code i noticed that they are using POJO class to interact with JSON, Is it is better way? if it is please explain why? cause using POJO means I have to write extra code, But if saving the response directly to the arraylist make my work done, then why should i use a POJO class?
So, Pojo usage better due to OOP pattern, because you work at runtime with your Java object without intermediate Json parse. Manual json parsing too ugly due to code style(its my opinion).
But if saving the response directly to the arraylist make my work done
If, you collect your object in Maps, you can apply different features out of the box(sort, compare etc) to your map, but in case when your map contains POJO instead of JSONS.
Encapsulation. When you work with dates for examples or with type, its pretty good to use getters/setters for data mapping instead of manual parsing again and again.
4.Object scaling and mapping:
Lets image that we have some object user:
public class User{
int id;
#SerializedName("specific_id_for_blah_blah")
private int mSpecId
#SerializedName("date_of_birthaday")
private String mBDay;
public Date getBirthday() {
return new Date(mBDay);
}
}
What I want to say by this example.
You can map your json to POJO with one line of code only
User user = new Gson.fromJson(response, User.class);
Pretty simple isn't?.
Name serialization. When your response contain key name which looks to long or weird, you can use your own style naming with easy changes, just with small annotation. mSpecId returns value of "specific_id_for_blah_blah"
Platform specific encapsulation. You can use only platform specific object at your runtime, instead parsing operations in your business logic. String with data -> Date or Calendar
Also you can override Object methods in your POJO (equals, hashcode, toString) for your logic spec. operations.
If your serverside change some key you can change name of key in POJO instead looking through where you parse it before. IN same case you can add new field and setter/getter, if some of parameter will be added to your response
There is no right and wrong answer here. It all depends on your use case. If your solution works, and you are happy with it, I don't see why do you need to change it.
If I had to choose, I would go with a POJO class to represent the response, but this is a subjective opinion. I think that you have the following benefits:
It's cleaner - having a separate, dedicated class to represent your payload gives you the ability to be more specific in your code. You are no longer manipulating Maps of key - value pairs, but instances of a specific class, that can have a more specific behaviour. You can specify natural ordering, criteria for equality, etc - things that may be useful for your program's logic
It's simpler - I would prefer calling a getter every time then accessing a map by a property name and getting an Object back. The logic of the program will be much simpler and safer.
It's better in terms of OOP best practices - the whole point behind OOP is to have objects, that define properties and behaviours. IMHO, using POJOs to represent responses forces you to adhere more closely to best practices.
There are also some cases that will fit the no - POJO approach better - for example, if you only display your data, not manipulating it in any way inside the app. Or if you want to shave off some time for the complex parsing that may be needed if you are trying to inflate object hierarchies.
My best suggestion is - profile your app, check your use cases and make an educated decision which approach is better.
Recently an interviewer asked me a very tricky question.
There are several parts of the question.
Why (question is why and not how) do you need to parcel objects while sending from one activity to another and not send directly
Answer I gave -
Parcelable gives the capability to developers to restrict object
creation which in a way makes it faster to use.
I was confused on the part, so decided to site difference between using serializable and parcelable :p (clever huuuhhh !),
http://www.developerphil.com/parcelable-vs-serializable/ used this reference.
While using Bundle, when we use String, int we do not need to parcel the data, so do you think the String/int is by default internally parcelled ?
Answer I gave -
because String/int is a primitive data-type, if we had used the
Wrapper class directly, might be possible we had to use parcelable(I
am not sure on that part)
I did not get any useful link after googling, also I or the interviewer is not quite satisfied with the answer.
If you guys can help, would be wonderful !
Why (question is why and not how) do you need to parcel objects while sending from one activity to another and not send directly
Parcelling/serializing objects isn't for speed as you had guessed.
When you're sending data between Activities, and especially between different applications (remember that Intent objects aren't only meant for communication between your own Activities, but are also for between yours and those of other apps as well), you cannot expect the sender and the receiver to have access to the same memory address spaces.
Android's documentation states that applications run in their own discrete memory spaces. Here's a quote to that effect from the docs:
Each process has its own virtual machine (VM), so an app's code runs in isolation from other apps.
So when you want to send an object myObject to some receiving Activity, you can't send its reference/pointer because the receiver won't necessarily have access to the location specified by the pointer. Instead you'll have to send some representation of myObject that the receiver can access and use -- this is why you need to marshall the data into a form that can be unmarshalled, and the easiest way to do so is to simply have the class of the object implement Serializable which lets Java do its best to convert the object into an array of bytes that can be easily sent to and unmarshalled by the receiver. But since Serializable uses reflection, this is slow.
You can use other ways that are faster to marshall the data -- one, for example, is converting the object into its JSON representation using a library like Gson and just sending it across since any JSON document can be represented as a String and easily converted back to a Java Object. Another way, which is probably faster in pretty much all cases is using the Parcelable interface which lets you specify exactly how you want to marshall the data and exactly how it should be unmarshalled. It basically gives you more control on the transmission of the object.
The tl:dr: Parcelling/Serializing etc is used because you can't send memory addresses across, so you have to send the actual data of the object and it has to be represented in some form.
While using Bundle, when we use String, int we do not need to parcel the data, so do you think the String/int is by default internally parcelled ?
How Bundle works internally is that it puts everything into a Map and parcels/unparcels the data as needed (ie when get/put is called). For putting Objects into a Bundle, the object's class needs to implement Serializable or Parcelable because it needs to tell the Bundle how it should be marshalled/unmarshalled internally.
But primitive types and Strings are simple enough and used often enough that the developer doesn't need to specify how that needs to happen and Bundle provides convenience methods for it. I can't give you a solid answer at the lowest level of how they works because a lot of the Parcel code is natively implemented and I couldn't find it online, but they must certainly be straightforward to convert to their representation in bytes.
Just to add what #uj- said, Parcelling/Serializing is needed as #uj- said it will be sent across JVMs so they need to be converted into some format so that the other party will be able to understand.
Let me take an example to explain why serializing/parcelling is needed,
you are sending data from an application written in "C++" to an application written in java, so the following are the classes,
In C++,
class Android {
public: int dataToSend; //for example purpose making field public and omitting setter/getters
}
In Java,
class Android{
public int dataToSend;
}
suppose the C++ code generates dynamic library (which will be generated by compiling using the standard C++ compiler and then linked), and Java code generates a jar (by compiling using the javac).
When the C++ application sends data (object of Android class) to the java application the way it is compiled and linked in C++ is completely different as compared to the way its compiled in java and hence java will be wondering what has this C++ application sent to me.
Hence to get rid of such problems serialisation/parcelling is needed which will make sure that both of the application know how the data is converting while transmitting through network (in case of android how it is transmitted to another activity, may be in same or different application).
And yea when we start comparing Serialisation and Parcelling, Parcelling gets the upper hand as we will be specifying the way the data must be converted when sending the data, else in the case of serialisation the object is converted to string using reflection and reflection always takes time. Hence Parcelling is faster compared to Serialisation.
For your second question,
if we consider the above example itself then we can say that String and int being primitive types (no user defined fields in them) and hence android will be able to handle the marshalling and unmarshalling of the data which will be sent.
I tried going through the code when we go on digging deeper we end up getting native code as said by #uj-.
Some extract from the android source code:
while writing the parcel:
parcel.writeInt(BUNDLE_MAGIC);
int startPos = parcel.dataPosition();
parcel.writeArrayMapInternal(mMap);
int endPos = parcel.dataPosition();
parcel.setDataPosition(lengthPos);
int length = endPos - startPos;
parcel.writeInt(length);
parcel.setDataPosition(endPos);
while reading the parcel,
int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
//noinspection ThrowableInstanceNeverThrown
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ Integer.toHexString(magic));
}
int offset = parcel.dataPosition();
parcel.setDataPosition(offset + length);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(parcel, offset, length);
p.setDataPosition(0);
mParcelledData = p;
set the magic number which will identify the start of the parcel while writing and the same will be used while we read the parcel.
Hope I answered your question.
I am working on a client server application, the server is in Delphi and I am using indy and using packed records for sending/receiving data, on the Android side I was able to find a library named javolution for converting the bytes array to class form so I can easily read the data from received packets or send data.
A normal Packet class looks like this:
class clsCommunicatorPacket extends Struct{
Unsigned16 signature = new Unsigned16();
Unsigned32 version = new Unsigned32();
Unsigned8 dataType = new Unsigned8();
Unsigned16 bufferSize = new Unsigned16();
public boolean isPacked() {
return true; // MyStruct is packed.
}
public ByteOrder byteOrder() {
// TopStruct and its inner structs use hardware byte order.
return ByteOrder.nativeOrder();
}
}
Everything is working as it is supposed to so far and am having no issue, but there will be more than a 100 types of packets and I need to store them in one place so I can access/create it from any activity for sending/receiving.
What I am thinking of doing is create a class file lets say clsAllPackets and then put all the packet classes in that class file.
And when I need to access a specific packet class I can instantiate it like this:
clsCommunicatorPacket Pck = new clsAllPackets().new clsCommunicatorPacket();
So every time I need a class packet I have to instantiate the whole upper class too...
I want to know what will be the consequences of this and how will this effect the performance of the application and what is the best alternative performance wise?
If you make the nested class static, it can be instantiated without having an instance of its outer class. Also, that syntax for instantiating a nested class is incorrect, it should be
new clsAllPackets.clsCommunicatorPacket();
The response I got to my previous question :
https://stackoverflow.com/questions/15489956/sending-data-structure-through-byte-android
states that I should look into serialization for converting my data to a byte array for transfer via bluetooth.
I have been looking into it but can't find any definite answer that states whether I am able to transfer a whole instance of an object, I was originally thinking of sending several arrays but now I am thinking maybe I can just create an object:
"Test"
parameters:
Test Name - String
Questions - Array of Strings
Question Answers - Array of Strings
Correct Answers - Array of Ints
My programming isn't that great so I was wondering, could I create this class, let the user on one device construct an object and then pass THAT object itself on through serialization (as shown in Java Serializable Object to Byte Array)
Will this ACTUALLY fully work and give me a whole object on the other system from which I can access the data elements I need?
Sorry if this is a stupid question but as I stated before my programming isn't that great and so I get confused sometimes :(
Thanks!
could I create
this class, let the user on one device construct an object and then
pass THAT object itself on through serialization
Short answer: Yes
But don't forget that class have to implement Serializable interface or NotSerializableException will be thrown.
Will this ACTUALLY fully work and give me a whole object on the other
system from which I can access the data elements I need?
Yes but this "other system" must know about this class. So if you create class
public class Foo implements Serializable {
private String name;
private int age;
// getters and setters
}
Application that want to deserialize object, must have this class in build path, simply said.
Say I have a Java Bean object which is serializable. I want to store it away safely when an Activity goes through onDestroy() on purpose (i.e. onSaveInstanceState() is not called).
I am looking for a way which doesn't involve creating a database and write the object to that (mostly since a) Android's DB API is horrible and b) since databases make application updates a nightmare, because there is no decent support for applying migrations).
I thought about serializing the object to a ByteArrayOutputStream, base64 encode that and write it to a SharedPreferences file as a string. Or is that too far off?
UPDATE
Maybe that serialize-to-string idea wasn't that bad after all, seems to work out pretty well. Here's what I'm doing now:
public static String objectToString(Serializable object) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
new ObjectOutputStream(out).writeObject(object);
byte[] data = out.toByteArray();
out.close();
out = new ByteArrayOutputStream();
Base64OutputStream b64 = new Base64OutputStream(out);
b64.write(data);
b64.close();
out.close();
return new String(out.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Object stringToObject(String encodedObject) {
try {
return new ObjectInputStream(new Base64InputStream(
new ByteArrayInputStream(encodedObject.getBytes()))).readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
in onDestroy() I can then simply write the Base64 string to a preference file, where it's safe until I read it again during the next activity launch. It's a lot faster than I expected and unless your beans carry huge amounts of data, it works pretty well. And even better, you don't have to maintain a DB schema.
Still, I'm curious about how others do this.
I am looking for a way which doesn't
involve creating a database and write
the object to that (mostly since a)
Android's DB API is horrible and b)
since databases make application
updates a nightmare, because there is
no decent support for applying
migrations).
Android's API is actually fairly reasonable, mostly because it's a thin wrapper over the SQLite API, and the SQLite API is fairly reasonable for an embedded database. Moreover, Android does provide assistance for schema upgrades on app upgrades, via SQLiteOpenHelper.
It's a lot faster than I expected and
unless your beans carry huge amounts
of data, it works pretty well.
I have heard of many more developers running away screaming from serialization than I have heard of people having long term success with it. Just within the past few days, here on SO #android, I had an exchange with somebody trying desperately to rip serialization out of his app by the roots.
And even better, you don't have to maintain a DB schema.
Oh yes you do. What do you think is going to happen when you update your application and your class is modified? Doing the bookkeeping to figure out how to deserialize old versions of the class from a new version of a class is a chore and is one of the reasons developers abandon serialization. Also, do not forget that serialization is not transactional, whereas SQLite is.
I was also looking for a nice approach of un/marshalling any beans or activity states. We all know how much Activity's onStoreInstanceState() and onRestoreInstanceState() is a pain.
My acitivities simply store their states in onPause() and restore them in onCreate() lifecycle hooks via direct object serialization.
Serialization via a String like you do, is of course possible but less suitable for big data and causes a lot of overhead. Moreover Preferences are actually there to store preferences, not data :) Unfortunately, the Parcelable / Parcel what we could use for this purpose, does not recommend to store to persistent storage.
So what's left over is a simple object serialization - fortunately android SDK has implementation of the ObjectInputStream and ObjectOutputStream classes with all drawbacks and benefits - like we would also do in a non-android Java world, a simple:
ObjectOutputStream.writeObject(yourPojo)
would do the magic for us, (remember to implement the Serializable marker-interface)
Also, you may want to look in following APIs of a Context - ContextWrapper - Activity, which are very useful to cache local data (such as images) etc:
.getCacheDir()
.getDir()
.openFileInput()
.openFileOutput()
happy hacking :)