2012-01-11 83 views
2

我需要序列化一个GeoPoints列表,然后将它们读回来。我搜索了网页,发现我可以实现自己的GeoPoint并实现可序列化。它的工作原理是,我可以将对象写入一个.ser文件,但是当我读回来时,我得到了一个invalidclassexception,它继续说详细信息 - 对原始GeoPoint对象的illegalaccessexception。我假设我没有正确地在MyGeoPoint类中扩展GeoPoint。有人可以看看并告诉我我犯了什么错误吗?扩展可序列化的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 
+0

ü也应该关闭FileOutputStream对象 - 序列化部分 – xyz 2012-01-11 10:15:42

+0

@xyz后F:自动关闭外部流关闭内部流(请参阅[这里](http://java.sun.com/developer/technicalArticles/Streams/ProgIOStreams/))。但'close()'应该在'finally'块中调用。 – Kai 2012-01-11 10:40:54

回答

4

的问题是,GeoPoint没有一个无参数的构造函数,见Serializable的JavaDoc:

允许的亚型不可序列化的类将被序列化, 子类型可能承担保存和恢复超类型公共状态 的责任,保护和(如果可访问)包 字段。子类型只有在它所扩展的类 有一个可访问的无参数构造函数来初始化类的状态时才可以承担这种责任。如果这个 不是这种情况,那么声明一个类Serializable是错误的。该错误将在运行时检测到。

InvalidClassException

当Serialization运行时检测到下列 问题一类一个抛出该异常的JavaDoc。

  • 类的串行版本不匹配,从流中读取类描述符的
  • 类包含未知数据类型
  • 类没有可访问的无参数的构造函数
0

只是为了让这个答案更加完整,我试图用一个bandaid修复来解决这个问题。尝试添加以下行类的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()); 
} 
1

你并不需要延长com.google.android.maps.GeoPoint有一个序列化对象来存储您的纬度/经度坐标。

因为你不拥有原始对象,所以你不应该这样做,因为如果Google决定改变原来的GeoPoint并且让我们说...添加/删除方法,更改方法签名等......你可能会得到陷入困境。

更糟糕的是,您的代码不可移植,因此Kindle Fire上的FYI Android无法访问Google Maps API,因此您的应用程序无法继续使用com.google.android.maps.GeoPoint。

去的方法是创建具有相同的确切属性(及其类型)来存储您的LAT一个序列化的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%,你的代码将被移植到Android设备在谷歌地图API不存在...如果这是这种情况下,只需导入你所拥有的任何地图库(例如ESRI或OpenSignalMaps),并获得他们的“GeoPoints”或等价对象之一,其坐标来自您自己的反序列化对象。

干杯!

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; 
}