2013-10-06 9 views
6

Una cosa che non mi è mai piaciuta di Gson è il fatto che devi passare un oggetto Class o TypeToken se stai ricevendo un oggetto o un elenco di oggetti . Ora, quando provo a usare Volley con Gson, questo problema persiste e sto cercando di creare una classe GsonRequest che possa essere utilizzata per entrambe le cose.Utilizzo di Volley e Gson: Parse voce e lista articoli

La mia soluzione è abbastanza brutta, due diversi costruttori: uno che ottiene un parametro Class<T> e un altro che ottiene un parametro Type. Quindi, nel numero parseNetworkResponse, viene chiamato gson.fromJson con uno dei campi, tenendo presente che uno deve essere null.

Qualche idea su come implementarlo in un modo migliore? (Non mi piace avere un GsonRequest e un GsonCollectionRequest classi quasi uguali)

Il mio codice, qui:

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

Classe 'Class' implementa effettivamente l'interfaccia' Tipo' quindi non si è realmente un costruttore che accetta 'Class' come argomento. –

+0

Humm ... ero quasi sicuro di aver avuto qualche errore nel passare un 'Type' a' gson.fromJson' quando volevo solo un oggetto per essere analizzato. Comunque, l'ho appena provato usando 'Type' e ha funzionato così forse ho solo bisogno di usare' Type' come dici tu. Pubblicalo come risposta e lo accetto :) – luixal

+0

Dai un'occhiata a questo articolo che spiega esattamente questo. https://goo.gl/nl2DfN – Sotti

risposta

3

È possibile creare una nuova GsonRequest utilizzando TypeToken come parametro Type.

Utilizzare GsonRequest generico come GsonRequest.

Creare una semplice richiesta di una classe GSON ...

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

o creare un tipo per un ArrayList ...

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

hai bisogno di aggiungere un nuovo costruttore/diverso alla tua classe gsonRequest? – Zapnologica

+0

L'esempio non funziona per me, hai usato questo codice? – Zapnologica

+0

Sì, e funziona per me. Potresti essere più specifico? Che tipo di errore ottieni? – jgonza73

0

ho usato la richiesta JsonObject del Volley e utilizzati Response.ToString() per analizzare la stringa JSON in Class attraverso Gson.

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

Ora avete obj con tutti i dati.

+0

Ciò tuttavia non esegue l'analisi sul thread di lavoro. – Zapnologica

3

Ho utilizzato il seguente metodo per analizzare un elenco JSON. Come prima cosa non inviare una classe nel costruttore, ma passare la classe Type dal pacchetto reflect.

La mia classe si presenta così:

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

}

La linea T parseObject = gson.fromJson(json, type); è importante impostare prima di chiamare il metodo Request.success.

+0

Grazie. Utilizzato il metodo parseNetworkResponse (...) per il tipo di parametro. Funzionando bene. – Godekere