使用Volley和Gson:解析条目和项目列表

6
我从未喜欢过Gson的一件事情,那就是你必须传递一个基于Class对象或TypeToken,根据你是否获取项或项列表。现在,当尝试使用Volley和Gson时,这个问题仍然存在,我正在尝试创建一个可以用于两种情况的GsonRequest类。

我的解决方案相当丑陋,有两个不同的构造函数:一个获取Class<T>参数,另一个获取Type参数。然后,在parseNetworkResponse中,使用其中之一调用gson.fromJson,记住其中一个必须为null

有什么更好的实现方法吗?(我不喜欢几乎相等的GsonRequestGsonCollectionRequest类)

我的代码如下:

public class GsonRequest<T> extends Request<T> {

    private final Gson gson;
    private final Class<T> clazz;
    private final Type type;
    private final Listener<T> listener;
    private final Map<String, String> headers;
    private final Map<String, String> params;

    public GsonRequest(int method, String url, Gson gson, Class<T> clazz, Map<String, String> headers, Map<String, String> params, Listener<T> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.gson = gson;
        this.clazz = clazz;
        this.type = null;
        this.listener = listener;
        this.headers = headers;
        this.params = params;
    }

    public GsonRequest(int method, String url, Gson gson, Type type, Map<String, String> headers, Map<String, String> params, Listener<T> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.gson = gson;
        this.clazz = null;
        this.type = type;
        this.listener = listener;
        this.headers = headers;
        this.params = params;
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return this.headers != null ? this.headers : super.getHeaders();
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return this.params != null ? this.params : super.getParams();
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {

            if (this.clazz != null) {
                return Response.success(
                        this.gson.fromJson(new String(response.data, HttpHeaderParser.parseCharset(response.headers)), this.clazz),
                        HttpHeaderParser.parseCacheHeaders(response));
            } else {
                return (Response<T>) Response.success(
                        this.gson.fromJson(new String(response.data, HttpHeaderParser.parseCharset(response.headers)), this.type),
                        HttpHeaderParser.parseCacheHeaders(response));
            }

        } catch (JsonSyntaxException e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(T response) {
        this.listener.onResponse(response);
    }

}

Class实际上实现了Type接口,因此您不需要一个以Class为参数的构造函数。 - Vladimir Mironov
嗯...我几乎确定在将“Type”传递给“gson.fromJson”时出现了一些错误,当我只想解析一个项目时。无论如何,我刚刚尝试使用“Type”,它可以工作,所以也许我只需要像你说的那样使用“Type”。把它作为答案发布,我会接受它 :) - luixal
看一下这篇文章,它详细解释了这个问题。https://goo.gl/nl2DfN - Sotti
3个回答

5
我使用了以下方法来解析JSON列表。 首先,不要在构造函数中发送Class,而是传递reflect包中的Type类。
我的类看起来像这样:
public class DownloadRequest<T> extends Request<T> {

private final Gson gson = new Gson();
private final Type type;
private final Map<String, String> params;
private final Response.Listener<T> listener;

public DownloadRequest(int method, String url, Map<String, String> params, Type type, Response.Listener<T> listener, Response.ErrorListener errorListener) {
    super(method, url, errorListener);
    this.type = type;
    this.params = params;
    this.listener = listener;
}

@Override
protected Response<T> parseNetworkResponse(NetworkResponse networkResponse) {

    try {
        String json = new String(networkResponse.data, HttpHeaderParser.parseCharset(networkResponse.headers));
        T parseObject = gson.fromJson(json, type);
        return Response.success(parseObject,HttpHeaderParser.parseCacheHeaders(networkResponse));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    return null;
}

@Override
protected void deliverResponse(T t) {
    listener.onResponse(t);
}

在调用 Request.success 方法之前,重要的是设置 T parseObject = gson.fromJson(json, type); 这一行。


谢谢。我使用了您的parseNetworkResponse(...)方法来处理参数类型,现在一切正常。 - Godekere

3
你可以使用TypeToken作为类型参数创建新的GsonRequest。
像这个GsonRequest一样使用通用GsonRequest。
为Gson类创建一个简单的请求...
new GsonRequest<MyClass>(Request.Method.GET, uriBuilder.build().toString(),
                    MyClass.class, null, mResponseListener, mReponseErrorListener));

或者为ArrayList创建一个类型...
Type type = new TypeToken<ArrayList<MyClass>>() {}.getType();
new GsonRequest<ArrayList<MyClass>>(Request.Method.GET, uriBuilder.build().toString(),
                    type, null, mResponseListListener, mReponseErrorListener));

您需要为您的gsonRequest类添加一个新的/不同的构造函数吗? - Zapnologica
是的,它对我有效。你能更具体地说明吗?你遇到了什么样的错误? - jgonza73
在尝试使用TypeToken时遇到了相同的问题。请更新您的GsonRequest类,使其在构造函数中接受Type而不是Class。同时,请按照Tooroop在他的答案中所做的方式更改parseNetworkResponse中解析JSON的方法。 - Justin Lucas

0
我使用了Volley的JsonObject请求,并使用Response.ToString()通过Gson将Json字符串解析为类。
Gson gson = new Gson();
ClassName obj = gson.fromJson(response.ToString(),ClassName.class);

现在你有一个包含所有数据的 obj 对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接