Java Serializable vs Android Parcelable
Posted
技术标签:
【中文标题】Java Serializable vs Android Parcelable【英文标题】: 【发布时间】:2019-01-11 12:52:41 【问题描述】:我目前正在开发一个 android 应用程序(我是开发 Android 应用程序的初学者),我正在实现一个非常简单的类,它能够处理位置(纬度、经度)和相应的地址(通过使用地理编码器 API)。 我希望我的应用能够在两个 Activity 之间传输我的类的一个实例,并返回结果,这样的结果也是该类的一个实例。
我已经编写了我的类的声明来实现 Parcelable 类,像这样(我的类名是 OnePlace):
public class OnePlace implements Parcelable
private LatLng position;
private String address;
…
我已经实现了“OnePlace”类,其方法能够实现 Parcelable,正如 Android 开发人员在线文档中推荐的那样: https://developer.android.com/reference/android/os/Parcelable
一切正常,我能够将我的类的一个实例从一个活动转移到另一个活动,然后再取回另一个实例。
这是我添加类的实例作为与意图一起发送的数据的 sn-p 代码:
OnePlace item = new OnePlace(); // create an instance of the class with default values
Intent mapIntent = new Intent(adapterView.getContext(), MapsActivity.class);
mapIntent.putExtra("place", item); // add the item as extra data to the intent
startActivityForResult(mapIntent, 35);
在被调用的活动(此处为 MapsActivity)中,我能够重建类实例的精确副本。
无论如何,这行得通,我对此很满意。
现在,我想将我的类的实例存储在一个文件中,当我下次启动我的应用程序时将读取该文件(一种永久存储的方法)。
为此,我在我的活动的 finish() 方法中使用以下代码 sn-p(就在离开我的应用程序之前):
FileOutputStream outStream = openFileOutput("myFile.tmp", Context.MODE_PRIVATE);
ObjectOutputStream objectStream = new ObjectOutputStream(outStream);
objectStream.writeObject(item);
objectStream.close();
outStream.close();
如您所见,我使用 ObjectOutputStream 类和 FileOutputStream 类来写入文件。 item 对象是我的 OnePlace 类的一个实例。我想将这个实例永久存储到一个文件中,以便下次能够取回它。
当我调用 writeObject(...) 方法时,调用以异常“Object not serializable”结束。看了一些网上的文档,明确的说我要“序列化”的类要实现Serializable接口(这个是强制的!)。
因此,我像这样更新了类的定义:
public class OnePlace implements Parcelable, Serializable
private LatLng position;
private String address;
…
我稍微修改了我的类的定义以实现 Parcelable 和 Serializable 接口。我不知道这是否是满足我需求的最佳方式……
当我想调用 intent.putExtra("key", item); 时,出现错误。事实上,Java 编译器抱怨它不知道它应该实现哪个 putExtra 接口:带有 Parcelable 接口的接口还是带有 Serializable 接口的接口?它的反应似乎是合乎逻辑的,我认为如果我是人类编译器,我可能会问同样的问题。
那么,现在,我该如何解决这个问题?有人有想法吗?也许,我想实现我的两个目标(将类实例转移到另一个活动并永久存储一个实例)的方式不是最好的方式?你有什么建议吗?
非常感谢您的回答。
查尔斯
【问题讨论】:
我可能会通过 GSON 序列化为文本,或者序列化到数据库(Room、Realm、ObjectBox 等) Android: Difference between Parcelable and Serializable?的可能重复 我读到有一些可能性可以将类实例“导出”到 JSON 对象中。我想我会试一试…… 【参考方案1】:最后,我设法找到了一个我觉得方便的优雅解决方案。我只是想发布我是如何做到的,如果它对寻找序列化对象的其他人有任何兴趣。
在我的 OnePlace 类的声明中,我最终只实现了 Parcelable 接口,以便能够在两个活动之间传输该类的实例(我没有实现 Serialize 接口)。
public class OnePlace implements Parcelable
private LatLng position;
private String address;
…
;
然后,我在我的类中添加了以下新方法:
public String toJSON()
JSONObject jsonObj = new JSONObject();
try
jsonObj.put("address", address);
jsonObj.put("latitude", position.latitude);
jsonObj.put("longitude", position.longitude);
return jsonObj.toString();
catch (Exception e)
e.printStackTrace();
return "";
该方法创建一个包含位置信息(地址、纬度和经度)的 JSON 对象,然后返回等效字符串(这将用于进一步导出位置信息)。
然后,在我的 MainActivity.finish() 方法中,我构建了一个字符串数组列表,每个字符串都包含与 OnePlace 类实例关联的 JSON 对象的字符串表示形式。 完成后,我就可以序列化我的 ArrayList 了,然后可以序列化(Java 编译器不会抱怨!)。这给了我一个长字符串,我写在我的应用偏好中。
代码如下:
public void finish()
ArrayList<String> listInstances = new ArrayList<String>();
for(OnePlace item: listOfPlaces)
listInstances.add(item.toJSON());
try
ObjectSerializer objSerializer = new ObjectSerializer();
String serializedStr = objSerializer.serialize(listInstances);
myPrefs.edit().putString("places", serializedStr).apply();
catch (Exception e)
e.printStackTrace();
现在,在我的 MainActivity.onCreate() 方法中,我从应用首选项中读回字符串并将其转换回 OneClass 实例,如下所示:
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// This is an array list that will contain all OnePlace instances
listOfPlaces = new ArrayList<OnePlace>();
myPreferences = this.getSharedPreferences("…", MODE_PRIVATE);
// I read back the String containing the serialized ArrayList
String placesStr = myPreferences.getString("places");
// An array list that will contain the list of JSONObjects, one object representing one instance on the OnePlace class
ArrayList<String> jsonObjList;
// I create a new ObjectSerializer object
ObjectSerializer objSerializer = new ObjectSerializer();
// Then, I deserialize into a list of JSONObjects
try
// The myList object contains a list of JSONObjects
jsonObjList = (ArrayList<String>)objSerializer.deserialize(placesStr);
// I loop through the list of JSONObjects
for(String str: jsonObjList)
// I create a JSONObject with one single string
JSONObject myJson = new JSONObject(str);
// Then, I get the values back and I use them to create a OnePlace class instance
LatLng position = new LatLng(myJson.getDouble("latitude"), myJson.getDouble("longitude"));
OnePlace myPlace = new OnePlace(position, myJson.getString("address");
// And finally, I add that OnePlace instance into my list of places
listOfPlaces.add(myPlace);
catch (Exception e)
e.printStackTrace();
;
所以,我在这里总结一下我是如何进行操作的:
对于保存过程,我执行以下操作:
-
将我的 OnePlace 类的每个实例导出为 JSONObject 字符串表示形式
将每个字符串添加到字符串数组列表中
完成后,数组列表被序列化
数组列表的序列化版本保存到应用首选项中
对于恢复过程,我执行以下操作:
-
从应用偏好中读取字符串
将该字符串反序列化为字符串数组列表
该数组列表中的每个字符串都用于创建 JSONObject
从 JSONObject 中提取位置信息
位置信息用于创建 OnePlace 类的实例
每个新实例都会添加到地点列表中
而且效果很好!
【讨论】:
【参考方案2】:我建议你在Activity、Fragments之间传递数据时使用Gson序列化。这是一个非常简单和轻量级的库。您的应用示例;
Gson gson = new Gson();
OnePlace item = new OnePlace(); // create an instance of the class with default values
Intent mapIntent = new Intent(adapterView.getContext(), MapsActivity.class);
mapIntent.putExtra("place", gson.toJson(item)); // add the item as extra data to the intent
startActivityForResult(mapIntent, 35);
在 MapsActivity.class 中
Gson gson = new Gson();
String jsonPlace = getIntent().getStringExtra("place");
Place passedItem = gson.fromJson(jsonPlace, Place.class);
【讨论】:
听起来很有趣。但是 OnePlace 类是否承诺可序列化以允许调用 gson.toJson(item) ?我的意思是我必须在我的类中实现任何可序列化的接口,比如 Serializable 或 Parcelable,还是我可以从我的类声明中完全删除它们? 你可以从你的类声明中完全删除它们以上是关于Java Serializable vs Android Parcelable的主要内容,如果未能解决你的问题,请参考以下文章
java.lang.NoSuchMethodError public default void android.content.ServiceConnection.onBindingDied(andr