2013-04-02 91 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(); 
    } 
}