RetroFit / GSON返回的列表似乎具有量子力学性质

时间:2016-02-02 15:16:02

标签: android gson retrofit parcelable

我正在使用带有GSON转换器的RetroFit 1.9,到目前为止我一直很好用。现在我正在尝试编组List中收到的Parcelable个自定义Callback个对象,我遇到了ClassCastException

02-02 09:53:49.921 13030-13030/com.example.app E/AndroidRuntime: FATAL EXCEPTION: main
            Process: com.example.app, PID: 13030
            java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to android.os.Parcelable
                at android.os.Parcel.writeTypedList(Parcel.java:1166)
                at com.example.common.util.ParcelableUtil.marshall(ParcelableUtil.java:37)
                at com.example.app.service.WearableMessageService$1.success(WearableMessageService.java:130)
                at com.example.app.service.WearableMessageService$1.success(WearableMessageService.java:120)
                at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:45)
                at android.os.Handler.handleCallback(Handler.java:739)
                at android.os.Handler.dispatchMessage(Handler.java:95)
                at android.os.Looper.loop(Looper.java:148)
                at android.app.ActivityThread.main(ActivityThread.java:5417)
                at java.lang.reflect.Method.invoke(Native Method)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

这是我的回调方法:

new Callback<List<MyObject>>() {
    @Override
    public void success(List<MyObject> objects, Response response) {
        mByteArray = ParcelableUtil.marshall(objects);
    }

    @Override
    public void success(RetrofitError error) {
        Timber.w("Failed to retrieve events, with message " + error.getMessage());
    }
}

所以我在success方法中添加了一个for循环,就在我调用ParcelableUtil.marshall()之前,测试为什么我得到的LinkedTreeMap对象列表而不是我的对象:

for(MyObject object : objects) {
    Timber.d(object.getTitle());
}

这不仅打印出每个对象的正确标题,奇迹般地其余代码也能正常工作! ParcelableUtil不再抛出错误,我收到一个字节数组,以后我可以完全解组。

LinkedTreeMap个对象列表在循环中观察之后如何更改为我的对象列表?为什么我首先得到LinkedTreeMap个对象的列表?这里发生了什么?

MyObject上课:

public class MyObject implements Parcelable {

    @SerializedName("title") private String mTitle;
    @SerializedName("location") private String mLocation;

    @SerializedName("start_date") private Date mStartDate;
    @SerializedName("end_date") private Date mEndDate;

    public MyObject() {
        /* Required empty constructor */
    }

    public Event(Parcel in) {
        mTitle = in.readString();
        mLocation = in.readString();

        mStartDate = new Date(in.readLong());
        mEndDate = new Date(in.readLong());
    }

    public String getTitle() {
        return mTitle;
    }

    public String getLocation() {
        return mLocation;
    }

    public void getStartDate() {
        return mStartDate();
    }

    public void getEndDate() {
        return mEndDate();
    }

    @Override
    public in describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mTitle);
        dest.writeString(mLocation);

        dest.writeLong(mStartDate.getTime());
        dest.writeLong(mEndDate.getTime());
    }

    public static final Creator<MyObject> CREATOR = new Creator<MyObject>() {
        @Override
        public MyObject createFromParcel(Parcel in) {
            return new MyObject(in);
        }

        @Override
        public MyObject[] newArray(int size) {
            return new MyObject[size];
        }
    };
}

MyObject的示例JSON Feed:

{
    "items": [
        {
            "title":"Object 1"
            "location":"Location 1"
            "start_date":"2016-02-02 15:30:00"
            "end_date":"2016-02-02 19:00:00"
        }
        {
            "title":"Object 2"
            "location":"Location 2"
            "start_date":"2016-02-02 18:00:00"
            "end_date":"2016-02-03 18:00:00"
        }
    ]
}

正在使用的GSON TypeAdapterFactory

public class DataAdapterFactory implements TypeAdapterFactory {

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {

        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<T>() {

            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            @Override
            public void read(JsonReader in) throws IOException {
                JsonElement jsonElement = elementAdapter.read(in);

                if(jsonElement.isJsonObject()) {
                    JsonObject jsonObject = jsonElement.getAsJsonObject();

                    if(jsonObject.has("items") && jsonObject.get("items".isJsonArray()) {
                        jsonElement = jsonObject.getAsJsonArray("items");
                    }

                    return delegate.fromJsonTree(jsonElement);
                }
            }
        }.nullSafe();
    }
}

1 个答案:

答案 0 :(得分:0)

啊,ProGuard,我存在的祸根......

今天早上我突然明白了。 ProGuard可能已经删除了该类,并且在for循环中使用该类必须告诉ProGuard该类实际上是需要的。我在ProGuard规则中添加了以下内容,现在无需循环循环即可使用:

-keep public class com.example.common.model.MyObject
-keep public class * implements com.example.common.model.MyObject
-keepclassmembers class com.example.common.model.MyObject {
    <methods>;
}

我相信在我的情况下我只需要第一行,但我认为其他的只会覆盖我的基础。