我想通过Socket传输一个Android对象,开销很低。 我应该使用标准的java.io.Serializable还是android.os.Parcel?
谢谢!
答案 0 :(得分:2)
都不是。
Parcel专为IPC而设计,其他用途虽然有效,但很危险。文档说
Parcel不是通用序列化机制。此类(以及用于将任意对象放入包中的相应Parcelable API)被设计为高性能IPC传输。因此,将任何Parcel数据放入持久存储中是不合适的:Parcel中任何数据的底层实现的更改都可能导致旧数据不可读。
这也意味着您需要确保远程端具有完全相同版本的Android和您的代码,以确保它能够正常工作。
Serializable有类似的问题,在(android)dcumentation中甚至有一个解决方案的暗示:
警告:此接口限制其实现类将来如何更改。通过实现Serializable,您可以将灵活的内存中实现细节公开为严格的二进制表示。简单的代码更改(如重命名私有字段)在更改的类可序列化时不安全。
[...]
推荐替代方案:JSON简洁,易读且高效。 Android包括流API和用于读写JSON的树API。使用像GSON这样的绑定库来直接读写Java对象。
如果您想将数据从一个设备移动到另一个设备,我认为您最好为数据创建协议,将其发送出去,并使用该数据填充远程对象。 JSON可能是一个很好的起点。
祝你好运!答案 1 :(得分:1)
通过套接字传输对象很大程度上取决于接收对象的内容。通常,这种传输依赖于基于文本的序列化,例如XML或JSON。
答案 2 :(得分:1)
如果您的邮件更长,更复杂,或者您需要更高效率,我建议您尝试使用Google Protocol Buffers。它们将允许一些合理数量的更改,例如添加新字段,或删除以前的可选字段,或添加一个全新的结构作为字段。然而,你也将拥有真正的setter和getter的真正的类(可以是不可变版本或可变构建器,你喜欢什么)。对你所做的更严格的控制并不像看起来那么糟糕。
思考XML,但更小,更快,更简单
序列化对象的主要缺点是不,以后您无法更改协议详细信息。不同的是,如果您引入版本号,则可以执行许多兼容的更改,如果您希望旧版客户端找到该属性,则无法在JSON中重命名属性名称。
然而,序列化对象是特定于Java的,您不能拥有更高效的C ++服务器客户端或使用Python进行原型设计,例如,如果您将来决定。协议缓冲区是语言中立的。
答案 3 :(得分:0)
首先,定义要发送的对象。例如,我们可以定义一个名为Message的类来封装我们的通信:
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;
}
}
接下来,实例化对象,将套接字的流包装在对象流中,然后通过套接字发送消息:
Message sayhey = new Message("123456789", "Hello");
Socket socket = new Socket(host, port);
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(sayhey);
在套接字的另一端,可以通过在返回的对象上调用方法来检索和使用该消息:
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Message messageObject = (Message) in.readObject();
String messageText = messageObject.getText();
您可以实现Serializable。