2013-04-02 56 views
4

我在android上写了一种游戏。我想知道如何保存设置,以免更新出现问题。 比如我保存设置系列化,我有类GameChar保存设置的实现

public class GameChar implements Serializable{ 

    int health; 
    int damage; 

    Sword sword; 
} 

但后来我决定价值装甲添加到我的游戏角色,我改变类:

public class GameChar implements Serializable{ 

    int health; 
    int damage; 

    int armor; 

    Sword sword; 
} 

现在有更新我松所有的进展,因为新类GameChar是不一样的GameChar。 我有一个想法,使用Map<String, Object>其中关键是价值的名称我保存和价值是任何Object我想(Integer,Float,Calendar或一些我的用户类Sword)。我将把这个Map保存到Serialization

但是,如果我更改了我的一些用户类Sword它将不会和我的Map中已经相同,并且我将再次更新进度。

也许有一些图案或技术,我想念,使其更优雅。

+1

怎么样,如果你使用像sqlite的基于文件/本地数据库DB。只保存变量。然后,当你有更新时,你可以添加任意数量的新变量,并简单地读回旧的变量值。 这是我如何解决我的问题,这是非常相似的。我没有注意到性能发生了重大变化,所以这是值得的。 –

回答

0

我想你应该看看到SharedPreferences(这是怎样的一个地图) http://developer.android.com/guide/topics/data/data-storage.html#pref

从你的榜样类

我会使用它,而不是连载类的所有,只是手动保存每一个人项目放入SharedPreferences中,并且永远不会有任何序列化问题。

+0

正如我在SharedPreferences中所理解的那样,我只能存储基元 - 这对我不利,因为我不仅应该存储基元,而且还要存储我的用户类,甚至它们的集合。 – sergant88

+0

使用'实现Serializable'你永远会遇到升级问题。因此,不管实际的方法是什么,建议存储原语并基于它们构建对象。我的回答是基于这样一个事实,即在问题中显示了一些相当简单的对象,但是如果您需要更健壮的数据存储方式,则需要使用数据库(SQLite) – Budius

2

您是否注意到,在执行Serializable时,您被要求声明一个static long,称为serialVersionUID

此变量的目的是在反序列化时检测旧版本的类。尝试使用版本2类从已保存的数据反序列化版本1将导致异常。

(你可以自己实现这一行为,如果你不使用Java的序列化设施,这只是一个数字和if

一旦检测到您保存的对象是陈旧的,并且不匹配当前的类定义,你可以手动修复这个问题。例如,如果您知道在版本2中声明了新成员int a;,并且您选取了一个序列号为1的对象,则可以指定一个值,尽管保存的信息中缺少该值。

不幸的是,跟踪版本是你的工作。最简单的方法是确保始终可以从较旧的版本实例化新版本,而无需进行调整 - 例如,null是一个有意义的值。

+0

这是正确的,可以从下行方面得到很好的建议因为它涉及到常规的Java序列化。尽管如此,我还是建议避免使用标准Java序列化来满足您在Android上的需求(对于您需要的方式而言,开销太大和复杂)。正如其他人所指出的,使用SharedPreferences(也就是说,使用具有属性的文件系统)或使用数据库。或者,我的最爱之一,使用Gson,并将json字符串序列化为文件。这是非常容易的,并把所有的辛苦工作放到Gson上。 –

+0

所以我应该手动设置serialVersionUID。并在旧版本的文件反序列化它仍然会被读取,但缺少字段将被设置为默认值,并知道serialVersionUID我应该为它设置相应的值? (因为现在当我没有手动设置serialVersionUID并添加一些字段到类我只是不能从文件中检索它 - 我得到例外) – sergant88

+0

正如查理所说,Java本机序列化是最好的避免。我只是使用纯静态整数版本和自定义反序列化方法中的“if”(没有抛出异常)。如果你想使用Java的工具,你可以[检查出来](http://docs.oracle.com/javase/7/docs/platform/serialization/spec/version.html) – slezica

0

“诀窍”是覆盖readObject方法并捕获发生序列化的以前版本GameChar时发生的EOFException。在豁免处理程序中,您可以为装甲分配一个默认值。由于这需要声明变量瞬态,所以还需要覆盖writeObject方法。这个例子不包含Sword,如果有不同版本的Sword(相同的过程),它本身应该覆盖readObject和writeObject方法。在超过2个版本的情况下,应使用变量“版本”并根据该变量的值读取对象。

public class GameChar implements Serializable { 

private static final long serialVersionUID = 12345L; // use serialver to determine UID 
transient private int health; 
transient private int damage; 
transient private int armor; 

private synchronized void writeObject(java.io.ObjectOutputStream s) 
     throws IOException { 
    s.writeInt(health); 
    s.writeInt(damage); 
    s.writeInt(armor); 

} 

private synchronized void readObject(java.io.ObjectInputStream s) 
     throws IOException, ClassNotFoundException { 
    health = s.readInt(); 
    damage = s.readInt(); 
    try { 
     armor = s.readInt(); 
    } catch (EOFException eofex) { 
     armor = 999; // default value 
    } 
} 
} 

如果使用这样的“版本”变量的readObject方法可能如下:

private synchronized void readObject(java.io.ObjectInputStream s) 
     throws IOException { 
    version = s.readInt(); 
    health = s.readInt(); 
    damage = s.readInt(); 
    switch(version) { 
     case 1: armor = 999; // default; 
      break; 
     case 2: armor = s.readInt(); 
    } 
}