2

我需要序列化一个 GeoPoints 列表,然后将它们读回。我在网上搜索,发现我可以实现自己的 GeoPoint 并实现可序列化。它可以工作,我可以将对象写入 .ser 文件,但是当我读回它时,我得到一个 invalidclassexception,它继续说详细消息 - 原始 GeoPoint 对象的非法访问异常。我假设我没有在 MyGeoPoint 类中正确扩展 GeoPoint。有人可以看看并告诉我我在哪里犯了错误吗?

import com.google.android.maps.GeoPoint;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MyGeoPoint extends GeoPoint implements Serializable {
static final long serialVersionUID = -3010695769693014199L;


public MyGeoPoint(int latitude, int longitude){
    super(latitude, longitude);
}
public MyGeoPoint(){
    this(0,0);
}
private void writeObject(ObjectOutputStream s) throws IOException{
    s.defaultWriteObject();
}
private void readObject(ObjectInputStream s)
        throws java.io.IOException, java.lang.ClassNotFoundException{
    s.defaultReadObject();
}
}

然后它就像

File filex = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator +"floodData.ser");
    MyGeoPoint aPoint = new MyGeoPoint();
    MyGeoPoint readPoint = null;
    //write
    try{
    FileOutputStream f = new FileOutputStream(filex);
    ObjectOutputStream s = new ObjectOutputStream(f);
    s.writeObject(aPoint);
    s.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

    //read
    try {
    FileInputStream ff = new FileInputStream(filex);
    ObjectInputStream ss = new ObjectInputStream(ff);
    readPoint = (MyGeoPoint)ss.readObject();
    ss.close();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } 
    catch (Exception e) {
        e.printStackTrace();
    } 
    //end serialisationtest 
4

4 回答 4

4

问题是GeoPoint没有无参数构造函数,请参阅Serializable的 JavaDoc :

为了允许序列化不可序列化类的子类型,子类型可以负责保存和恢复超类型的公共、受保护和(如果可访问)包字段的状态。仅当它扩展的类具有可访问的无参数构造函数来初始化类的状态时,子类型才可以承担此责任。如果不是这种情况,则声明类 Serializable 是错误的。将在运行时检测到错误。

以及InvalidClassException的 JavaDoc

当序列化运行时检测到类的以下问题之一时引发。

  • 类的串行版本与从流中读取的类描述符的版本不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造函数
于 2012-01-11T10:18:05.237 回答
1

您不需要扩展 com.google.android.maps.GeoPoint 来拥有一个可序列化的对象来存储您的纬度/经度坐标。

而且由于您不拥有原始对象,因此您不应该这样做,因为如果 Google 决定更改原始 GeoPoint 并假设...添加/删除方法、更改方法签名等...您可能会遇到麻烦。

更糟糕的是,您的代码不可移植,仅供参考,Kindle Fire 上的 Android 无法访问 Google Maps API,因此您从 com.google.android.maps.GeoPoint 扩展的应用程序将无法运行。

要走的路是创建一个具有相同确切属性(及其类型)的可序列化 POJO 来存储您将序列化的纬度/经度坐标:

package com.yourapp.beans;

public class YourGeoPoint implements Serializable {

        private static final long serialVersionUID = -99127398709809L;

        private int latitudeE6;
        private int longitudeE6;

        public YourGeoPoint() {
            this.setLatitudeE6(0);
            this.setLongitudeE6(0);
        }

        public YourGeoPoint(int latitudeE6, int longitudeE6) {
            this.setLatitudeE6(latitudeE6);
            this.setLongitudeE6(longitudeE6);
        }

        public int getLatitudeE6() {
            return latitudeE6;
        }

        public void setLatitudeE6(int latitudeE6) {
            this.latitudeE6 = latitudeE6;
        }

        public int getLongitudeE6() {
            return longitudeE6;
        }

        public void setLongitudeE6(int longitudeE6) {
            this.longitudeE6 = longitudeE6;
        }

    }

然后,每当您需要com.google.android.maps.GeoPoint ...并在反序列化为 yourGeoPoint 实例后,只需执行以下操作:

import com.google.android.maps.GeoPoint;
import com.yourapp.beans.YourGeoPoint;
//...    
YouGeoPoint yourGeoPoint = // De-serialization...        
GeoPoint geoPoint = new GeoPoint(yourGeoPoint.getLatitudeE6(), yourGeoPoint.getLongitudeE6());

它可以 100% 运行,并且您的代码将可移植到不存在 Google Maps API 的 Android 设备上……如果是这种情况,只需导入您有权访问的任何地图库(例如 ESRI 或 OpenSignalMaps)并获得一个他们的“GeoPoints”或等效对象的坐标来自您自己的反序列化对象。

干杯!

于 2012-11-10T02:00:48.377 回答
0

只是为了使这个答案更完整,我试图用创可贴修复来解决这个问题。尝试将以下行添加到类 writeObject 和 readObject...

private void writeObject(ObjectOutputStream s) throws IOException{
    s.writeInt(this.getLatitudeE6());
    s.writeInt(this.getLongitudeE6());
}
private void readObject(ObjectInputStream s)
        throws java.io.IOException, java.lang.ClassNotFoundException{
    this(s.readInt(), s.readInt());
}
于 2012-08-08T05:45:13.510 回答
0

一种不弄乱其他代码的更简洁的方法是将您的类 setter 和 getter 更改为:

private double lat;
private double lng;

public LatLng getLocation() {
    LatLng latLng = new LatLng(this.lat, this.lng);

    return latLng;
}

public void setLocation(LatLng location) {

    this.lat = location.latitude;
    this.lng = location.longitude;
}
于 2015-01-24T19:14:50.520 回答