2013-10-06 8 views
6

Eine Sache, die ich an Gson nie gemocht habe, ist die Tatsache, dass Sie ein Klassenobjekt oder ein TypeToken basierend darauf übergeben müssen, wenn Sie einen Gegenstand oder eine Liste von Gegenständen bekommen . Nun, wenn ich versuche, Volley mit Gson zu benutzen, bleibt dieses Problem bestehen und ich versuche eine GsonRequest-Klasse zu erstellen, die für beide Dinge verwendet werden kann.Verwenden von Volley und Gson: Objekt- und Elementliste analysieren

Meine Lösung ist ziemlich hässlich, zwei verschiedene Konstrukteure: eine bekommt einen Class<T> Parameter und eine andere erhält eine Type Parameter. Dann wird in der parseNetworkResponse, gson.fromJson mit einem der Felder aufgerufen, wobei zu beachten ist, dass man null sein muss.

Haben Sie eine Idee, wie Sie dies besser umsetzen können? (Ich weiß nicht wie ein GsonRequest und eine GsonCollectionRequest fast gleich Klassen mit)

Mein Code, hier:

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

} 
+0

Die Klasse 'Class' implementiert tatsächlich die' Type'-Schnittstelle, so dass Sie nicht wirklich einen Konstruktor haben, der 'Class' als Argument akzeptiert. –

+0

Humm ... ich war mir fast sicher, dass ich einen Fehler bekommen hatte, indem ich einen 'Type' an' gson.fromJson' übergeben habe, wenn ich nur ein Element geparst haben wollte. Wie auch immer, ich habe es gerade mit 'Type' ausprobiert und es hat funktioniert, vielleicht muss ich nur' Type' verwenden, wie du sagst. Post es als Antwort und ich werde es akzeptieren :) – luixal

+0

Werfen Sie einen Blick auf diesen Artikel, der genau das erklärt. https://goo.gl/nl2DfN – Sotti

Antwort

3

Sie können einen neuen GsonRequest erstellen TypeToken als Type-Parameter verwenden.

Verwenden Sie generische GsonRequest wie diese GsonRequest.

Erstellen Sie eine einfache Anfrage für eine Gson Klasse ...

new GsonRequest<MyClass>(Request.Method.GET, uriBuilder.build().toString(), 
        MyClass.class, null, mResponseListener, mReponseErrorListener)); 

oder einen Typ für eine Arraylist erstellen ...

Type type = new TypeToken<ArrayList<MyClass>>() {}.getType(); 
new GsonRequest<ArrayList<MyClass>>(Request.Method.GET, uriBuilder.build().toString(), 
        type, null, mResponseListListener, mReponseErrorListener)); 
+0

Müssen Sie Ihrer GsonRequest-Klasse einen neuen/anderen Konstruktor hinzufügen? – Zapnologica

+0

Ihr Beispiel funktioniert nicht für mich, haben Sie das im Code verwendet? – Zapnologica

+0

Ja, und es funktioniert für mich. Könnten Sie genauer sein? Was für einen Fehler hast du? – jgonza73

0

ich die JsonObject Antrag des Volley verwendet und gebraucht die Response.ToString(), um die JSON-Zeichenfolge über Gson zur Klasse zu analysieren.

Gson gson = new Gson(); 
ClassName obj = gson.fromJson(response.ToString(),ClassName.class); 

Jetzt haben Sie obj mit allen Daten.

+0

Dies tut jedoch nicht die Analyse auf dem Arbeitsthread. – Zapnologica

3

Ich habe die folgende Methode verwendet, um eine JSON-Liste zu analysieren. Senden Sie als Erstes keine Klasse im Konstruktor, sondern übergeben Sie die Type-Klasse aus dem reflect-Paket.

Meine Klasse sieht wie folgt aus:

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

}

Die Linie T parseObject = gson.fromJson(json, type); wichtig ist, zu setzen, bevor Sie die Request.success Methode aufrufen.

+0

Danke. Verwendete Ihre Methode parseNetworkResponse (...) für den Parametertyp. Funktioniert gut. – Godekere

Verwandte Themen