使用GSON序列化SparseArray <T>

Len*_*art 9 serialization android gson sharedpreferences

我想序列化一个自定义Java对象,所以我可以SharedPreferences用来存储它并在另一个Activity中检索它.我不需要持久存储,SharedPreferences我在应用程序关闭时擦除它们.我目前正在使用GSON,但它似乎不适用于Android的SparseArray类型.

我的对象:

public class PartProfile {

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

// ...
}

public class Part {
   private String partName;
   // More primitives
}
Run Code Online (Sandbox Code Playgroud)

连载:

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

serializeWithJSON():

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

反序列化:

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);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

例外:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.mypackage.objects.Part
Run Code Online (Sandbox Code Playgroud)

我不明白为什么Gson想要投射LinkedTreeMap到我的对象,我从来没有在我的整个程序中使用过.HashMap<Integer,Part>在我改用之前我曾经有过一次SparseArray<Part>,从来没有遇到过这个问题.Gson不支持SparseArrays,或者我这边有错误吗?

编辑:似乎SparseArray正确反序列化,但不是内部的对象.而不是LinkedTreeMaps,这些应该是类型Part.在此输入图像描述

dma*_*ato 13

真的有一种方法可以序列化任何一种SparseArray,这里有一个示例代码:

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

}
Run Code Online (Sandbox Code Playgroud)

并使用它你需要在你的Gson对象中注册它,如下所示:

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

你可以在这个要点中找到这个例子.

PS:我知道它根本没有优化,但它只是一个例子来说明如何实现你所需要的.


Hoà*_*ong 5

似乎SparseArray正确反序列化,但不是内部的对象.而不是LinkedTreeMaps,这些应该是Part类型.

你的观察是正确的,因为SparseArray包含Object(不是Part),Gson将没有任何线索将Part作为你的对象类型.因此,它将您的列表映射为其臭名昭着的内部类型LinkedTreeMap.

要解决它,我认为你将无法使用SparseArray...或者你可以尝试retreivedParts.get(key).toString(),然后使用gson再次解析对象.但我认为这样做并不高效