首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java Serializable vs Android Parcelable

Java Serializable vs Android Parcelable
EN

Stack Overflow用户
提问于 2018-08-03 15:26:45
回答 2查看 337关注 0票数 1

我目前正在开发一个Android应用程序(我是开发Android应用程序的初学者),我正在实现一个非常简单的类,它能够处理一个位置(纬度、经度)和相应的地址(使用Geocoder )。我希望我的应用程序能够在两个活动之间传输我的类的一个实例,并获得结果,这样的结果也是该类的一个实例。

我编写了类的声明来实现Parcelable类,如下所示(我的类名是OnePlace):

代码语言:javascript
复制
public class OnePlace implements Parcelable {

    private LatLng position;
    private String address;
    …
}

我使用方法实现了"OnePlace“类,以便能够实现Parcelable,这是文档中推荐的:https://developer.android.com/reference/android/os/Parcelable

一切都很好,我能够将类的一个实例从一个活动转移到另一个活动,并得到另一个实例作为结果。

下面是代码片段,在其中我将类的实例添加为与意图一起发送的数据:

代码语言:javascript
复制
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()方法中使用了以下代码片段(就在离开我的应用程序之前):

代码语言:javascript
复制
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(…)时方法时,调用以异常“对象不可序列化”结束。在阅读了一些在线文档之后,我们明确表示,我想要“序列化”的类应该实现可序列化接口(这是强制性的!)。

因此,我更新了类的定义如下:

代码语言:javascript
复制
public class OnePlace implements Parcelable, Serializable {
    private LatLng position;
    private String address;
    …

我稍微修改了类的定义,以实现Parcelable和Serializable接口。我不知道这是否是实现我的需要的最好方法…

当我想调用intent.putExtra("key",item)时,我会得到一个错误。实际上,Java编译器抱怨说它不知道它应该实现哪个putExtra接口:具有Parcelable的接口还是具有可序列化接口的?它的反应似乎是合乎逻辑的,我认为如果我是一个人类编译器,我可能会问同样的问题。

那么,现在,我该如何解决这个问题呢?有人有主意吗?也许,我想实现两个目标的方式(将类实例转移到另一个活动并永久存储实例)不是最好的方法吗?你有什么建议吗?

我提前感谢你的回答。

查尔斯

EN

回答 2

Stack Overflow用户

发布于 2018-08-11 05:33:09

最后,我设法找到了一个我觉得方便的优雅的解决方案。我只是想贴出我是如何做到的,如果它对其他寻找序列化对象的人有任何兴趣的话。

在我的OnePlace类的声明中,我最后只实现了Parcelable接口,以便能够在两个活动之间传输该类的实例(我不再实现序列化接口)。

代码语言:javascript
复制
public class OnePlace implements Parcelable {
    private LatLng position;
    private String address;
    …
};

然后,我在类中添加了以下新方法:

代码语言:javascript
复制
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编译器不会抱怨!)这给了我一个长字符串,我写在我的应用程序首选项。

以下是代码:

代码语言:javascript
复制
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()方法中,我从app首选项读取字符串,并将它转换回OneClass实例,如下所示:

代码语言:javascript
复制
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();
  };

所以,我在这里总结一下我是如何做手术的:

对于保存过程,我执行以下操作:

  1. 将我的OnePlace类的每个实例导出为JSONObject字符串表示形式
  2. 将每个字符串添加到字符串数组列表中
  3. 完成后,数组列表将被序列化。
  4. 数组列表的序列化版本保存到应用程序首选项中。

对于恢复过程,我做以下工作:

  1. 从应用程序首选项中读取字符串
  2. 将该字符串反序列化为字符串数组列表。
  3. 该数组列表中的每个字符串用于创建一个JSONObject。
  4. 从JSONObject中提取位置信息。
  5. 位置信息用于创建OnePlace类的实例。
  6. 每个新实例都被添加到位置列表中。

而且效果很好!

票数 0
EN

Stack Overflow用户

发布于 2018-08-11 06:02:53

我建议您在活动、片段之间传递数据时使用葛森序列化。这是非常简单和轻量级的库。例如你的应用程序;

代码语言:javascript
复制
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中

代码语言:javascript
复制
Gson gson = new  Gson();
String jsonPlace = getIntent().getStringExtra("place");
Place passedItem = gson.fromJson(jsonPlace, Place.class);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51675834

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档