2013-06-21 16 views
8

Chcę serializować niestandardowy obiekt Java, dzięki czemu mogę użyć go do zapisania go i odzyskania go w innym działaniu. Nie potrzebuję trwałego przechowywania, SharedPreferences, I wytrzeć je, gdy moja aplikacja jest zamknięta. Obecnie używam GSON, ale wygląda na to, że nie działa dobrze z typem SparseArray systemu Android.Serializing a SparseArray <T> z GSON

Moje obiekty:

public class PartProfile { 

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

// ... 
} 

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

serializacji:

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

deserializacjia:

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); 
    // ... 
} 

Wyjątek:

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

Nie rozumiem dlaczego Gson chce rzucić LinkedTreeMap do mojego obiektu, nigdy nie używać jednego w moim całego programu. Kiedyś miałem HashMap<Integer,Part> zanim przełączyłem się na SparseArray<Part> i nigdy nie miałem z tym problemów. Czy SparseArrays nie jest obsługiwany przez Gson, czy jest jakiś błąd po mojej stronie?

Edytuj: Wygląda na to, że SparseArray otrzymuje poprawnie deserializację, ale nie obiekty wewnątrz. Zamiast LinkedTreeMaps, powinny one być typu Part. enter image description here

+0

"SharedPreferences" utrzymuje się pomiędzy sesjami (nawet jeśli aplikacja zostanie zabita). Przeczytaj [Korzystanie z preferencji współdzielonych] (http://developer.android.com/guide/topics/data/data-storage.html # pref) – Rajesh

+0

Tak, ale wyczyściłem je ręcznie za pomocą clear(). Chciałem tylko wskazać, że utrzymanie ich nie jest konieczne. – Lennart

+0

'SharedPreferences' nie służy do udostępniania danych między działaniami. Więcej informacji można znaleźć na stronie http://stackoverflow.com/q/3549596/1321873. – Rajesh

Odpowiedz

5

Wydaje się, że SparseArray dostaje rozszeregować poprawnie, ale nie obiekty wewnątrz. Zamiast LinkedTreeMaps powinny one być typu Część.

Twoja obserwacja jest poprawna, ponieważ SparseArray zawiera Object (nie Part) Gson nie będzie miał żadnego pojęcia, aby udział jako typu obiektu. Dlatego też mapuje twoją listę jako jej niesławny typ wewnętrzny: LinkedTreeMap.

Aby go rozwiązać, myślę, że nie będziesz w stanie użyć SparseArray ... Możesz też wypróbować retreivedParts.get(key).toString(), a następnie użyć gson do ponownego przeanalizowania obiektu. Ale nie sądzę, że to skuteczne, aby zrobić

+0

Przyjmuję twoją odpowiedź, ponieważ nie wydaje się, że to właściwe rozwiązanie. Zamieniłem moje SparseArrays na HashMaps, ale musiałem użyć 'Gson gson = new GsonBuilder(). EnableComplexMapKeySerialization(). Create()' aby je przekształcić do postaci szeregowej, ponieważ w jakiś sposób moje obiekty niestandardowe nie zostały poprawnie sformatalizowane, bez włączonej tej opcji. – Lennart

12

Naprawdę nie ma sposobu, aby szeregować jakiejkolwiek SparseArray, oto przykładowy kod:

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

} 

i go używać trzeba go zarejestrować w obiekcie Gson coś takiego:

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

można znaleźć ten przykład w this gist.

P.S .: Wiem, że w ogóle nie jest zoptymalizowany, ale to tylko przykład, aby dać wyobrażenie o tym, jak osiągnąć to, czego potrzebujesz.

+0

Ten kod działa. Jednak nadal nie używam go jako rozwiązania, ponieważ SparseArray nie ma funkcji Parcable/Serializable. Dlatego jest mi bardzo trudno przekazać go innym działaniom i procesom. Koniec, wracam do HashMap. –

+0

Zostawię przyszły odnośnik https://gist.github.com/dmarcato/6455221 – Javier