2013-06-21 4 views
8

Ich möchte ein benutzerdefiniertes Java-Objekt serialisieren, so dass ich SharedPreferences verwenden kann, um es zu speichern und es in einer anderen Aktivität zu retreive. Ich brauche keinen dauerhaften Speicher, die SharedPreferences, lösche ich sie, wenn meine Anwendung geschlossen ist. Ich verwende derzeit GSON, aber es scheint nicht gut mit Android SparseArray Typ zu arbeiten.Serialisieren eines SparseArray <T> mit GSON

Meine Objekte:

public class PartProfile { 

private int gameId; 
// Some more primitives 
private SparseArray<Part> installedParts = new SparseArray<Part>(); 

// ... 
} 

public class Part { 
    private String partName; 
    // More primitives 
} 

Serialisierung:

Type genericType = new TypeToken<PartProfile>() {}.getType(); 
String serializedProfile = Helpers.serializeWithJSON(installedParts, genericType); 
preferences.edit().putString("Parts", serializedProfile).commit(); 

serializeWithJSON():

public static String serializeWithJSON(Object o, Type genericType) { 
    Gson gson = new Gson(); 
    return gson.toJson(o, genericType); 
} 

Deserialisierung:

Type genericType = new TypeToken<PartProfile>() {}.getType(); 
PartProfile parts = gson.fromJson(preferences.getString("Parts", "PARTS_ERROR"), genericType); 

SparseArray<Part> retreivedParts = parts.getInstalledParts(); 
int key; 
for (int i = 0; i < retreivedParts.size(); i++) { 
    key = retreivedParts.keyAt(i); 
    // Exception here: 
    Part part = retreivedParts.get(key); 
    // ... 
} 

Ausnahme:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.mypackage.objects.Part 

Ich verstehe nicht, warum Gson ein LinkedTreeMap auf mein Objekt werfen will, und ich habe nie in meinem ganzen Programm verwenden. Ich hatte eine HashMap<Integer,Part>, bevor ich auf die SparseArray<Part> wechselte, und hatte nie Probleme damit. Werden SparseArrays von Gson nicht unterstützt, oder liegt ein Fehler auf meiner Seite vor?

Bearbeiten: Es scheint, dass das SparseArray korrekt deserialisiert wird, aber nicht die Objekte darin. Anstelle von LinkedTreeMaps sollten diese vom Typ Part sein. enter image description here

+0

'SharedPreferences' bleiben für Sitzungen bestehen (selbst wenn die Anwendung beendet wird). Lesen Sie [Gemeinsame Einstellungen verwenden] (http://developer.android.com/guide/topics/data/data-storage).html # pref) – Rajesh

+0

Ja, aber ich wische sie manuell mit clear(). Ich wollte nur darauf hinweisen, dass es nicht notwendig ist, sie zu halten. – Lennart

+0

'SharedPreferences' sind nicht für die gemeinsame Nutzung von Daten gedacht. Weitere Informationen finden Sie unter http://stackoverflow.com/q/3549596/1321873. – Rajesh

Antwort

5

Es scheint, dass die SparseArray korrekt deserialisiert wird, aber nicht die Objekte im Inneren. Anstelle von LinkedTreeMaps sollten diese vom Typ sein.

Ihre Beobachtung richtig ist, da SparseArray enthält Objekt (nicht Part), Gson wird keine Ahnung haben, Teil als Objekttyp zu machen. Daher kartieren Sie Ihre Liste als berüchtigten internen Typ LinkedTreeMap.

Um es zu lösen, ich denke, Sie können SparseArray nicht verwenden ... Oder Sie versuchen retreivedParts.get(key).toString(), dann verwenden Sie Gson, um das Objekt erneut zu analysieren. Aber ich glaube nicht, es effizient ist zu tun, dass

+0

Ich werde Ihre Antwort akzeptieren, da es keine angemessene Lösung dafür zu geben scheint. Ich habe meine SparseArrays durch HashMaps ersetzt, aber ich musste 'Gson gson = new GsonBuilder(). EnableComplexMapKeySerialization(). Create()' verwenden, um sie zu serialisieren, da meine benutzerdefinierten Objekte ohne diese Option nicht richtig deserialisiert wurden. – Lennart

12

Wirklich es eine Möglichkeit ist, jede Art von SparseArray serialisiert werden, hier ist ein Beispielcode:

public class SparseArrayTypeAdapter<T> extends TypeAdapter<SparseArray<T>> { 

    private final Gson gson = new Gson(); 
    private final Class<T> classOfT; 
    private final Type typeOfSparseArrayOfT = new TypeToken<SparseArray<T>>() {}.getType(); 
    private final Type typeOfSparseArrayOfObject = new TypeToken<SparseArray<Object>>() {}.getType(); 

    public SparseArrayTypeAdapter(Class<T> classOfT) { 
     this.classOfT = classOfT; 
    } 

    @Override 
    public void write(JsonWriter jsonWriter, SparseArray<T> tSparseArray) throws IOException { 
     if (tSparseArray == null) { 
      jsonWriter.nullValue(); 
      return; 
     } 
     gson.toJson(gson.toJsonTree(tSparseArray, typeOfSparseArrayOfT), jsonWriter); 
    } 

    @Override 
    public SparseArray<T> read(JsonReader jsonReader) throws IOException { 
     if (jsonReader.peek() == JsonToken.NULL) { 
      jsonReader.nextNull(); 
      return null; 
     } 
     SparseArray<Object> temp = gson.fromJson(jsonReader, typeOfSparseArrayOfObject); 
     SparseArray<T> result = new SparseArray<T>(temp.size()); 
     int key; 
     JsonElement tElement; 
     for (int i = 0; i < temp.size(); i++) { 
      key = temp.keyAt(i); 
      tElement = gson.toJsonTree(temp.get(key)); 
      result.put(key, gson.fromJson(tElement, classOfT)); 
     } 
     return result; 
    } 

} 

und es zu benutzen Sie müssen es registrieren in Ihrem Gson Objekt, wie folgt aus:

Type sparseArrayType = new TypeToken<SparseArray<MyCustomClass>>() {}.getType(); 
Gson gson = new GsonBuilder() 
    .registerTypeAdapter(sparseArrayType, new SparseArrayTypeAdapter<MyCustomClass>(MyCustomClass.class)) 
    .create(); 

können Sie dieses Beispiel in this gist finden.

S.S .: Ich weiß, dass es überhaupt nicht optimiert ist, aber es ist nur ein Beispiel, um eine Vorstellung davon zu geben, wie man das erreicht, was man braucht.

+0

Dieser Code funktioniert. Allerdings verwende ich es immer noch nicht als Lösung, da SparseArray nicht Parcable/Serializable ist. Daher ist es ziemlich schwierig für mich, sie an verschiedene Aktivitäten und Prozesse weiterzugeben. Am Ende, ich falle zurück zu HashMap. –

+0

Ich werde eine zukünftige Referenz https://gist.github.com/dmarcato/6455221 hinterlassen – Javier