2014-09-10 12 views
7

Sto cercando di ridefinire il mio codice per utilizzare Retrofit (da Volley) per alcune chiamate API Foursquare ma non ho trovato un esempio corretto che mostra come specificare un parametro di query che ha 2 valori separati da una virgola.Retrofit: come specificare i parametri separati da virgole nella richiesta?

mio URL di base è la seguente:

public static final String VENUES_BASE_URL = "https://api.foursquare.com/v2/venues"; 

Il resto del mio URL è simile a questo:

"?ll=40.7,50.2&limit=50&radius=25000&v=20140909&venuePhotos=1&oauth_token=xxyyxx"; 

prima implementazione per la mia interfaccia:

public interface Fourquare { 
    @GET("/explore?ll={p1},{p2}&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") 
    Response getVenues(@Path("p1") String param1, 
        @Path("p2") String param2); 

} 

E quindi fatto la richiesta in questo modo:

RestAdapter restAdapter = new RestAdapter.Builder() 
      .setEndpoint(ConfigConstants.VENUES_BASE_URL) 
      .build(); 

    Fourquare fourquare = restAdapter.create(Fourquare.class); 
    Response myResponse = fourquare.getVenues("50", "75"); 

Tuttavia, quanto sopra mi ha dato il seguente errore:

retrofit.RetrofitError: Fourquare.getVenues: URL query string "ll={p1},{p2}&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx" must not have replace block. 

seconda implementazione (Dopo aver esaminato alcune delle risposte SO che utilizzano parametri query. NOTA: una volta capito il ll? parametri di richiamo avrò il token come parametro):

@GET("/explore&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") 
void getVenues(@Query("ll") String ll, 
         Callback<String> cb); 

Con la chiamata effettiva in questo modo:

fourquare.getVenues("50,75", new Callback<String>() { 
     @Override 
     public void success(String s, Response response) { 
      Log.d(TAG, "Successful run!"); 
     } 

     @Override 
     public void failure(RetrofitError error) { 
      Log.d(TAG, "Failed run!"); 
     } 
    }); 

Con l'attuazione di sopra del metodo di fallimento() è sempre sempre chiamato, quindi non c'è c'è ancora qualcosa che non va nel mio codice. Qualcuno può dare qualche suggerimento sul modo corretto di implementare questa chiamata? Sono certo che il problema è con il "ll?" parametro.

Aggiornamento: Dopo aver registrando questo è l'URL finale sto ottenendo da Retrofit:? https://api.foursquare.com/v2/venues/explore&limit=50&radius=25000&v=20140909&venuePhotos=1&oauth_token=xxyyxx?ll=30.26%2C-97.74

Sembra che il server di Foursquare non piace il parametro ll alla fine dell'URL e deve essere posizionato esplicitamente subito dopo ../v2/venues/explore in quanto funziona correttamente quando si effettua una richiesta attraverso il browser.

Qualsiasi soluzione per aggirare questa limitazione dall'API?

3a implementazione (9/17/14) Con il suggerimento colriot Sono riuscito a risolvere il codice di risposta 400 che stavo ottenendo con la mia precedente implementazione. Sto ancora avendo un problema di velocità con GSON, quindi sono alla ricerca di suggerimenti su come risolverlo. Nello specifico, la mia implementazione Retrofit richiede più tempo per visualizzare i miei risultati rispetto a Volley, quindi mi chiedo se esiste un modo migliore per implementare la funzione di callback.

interfaccia Foursquare

public interface Fourquare { 
    @GET("/explore?limit=50&radius=25000&v=20140909&venuePhotos=1&oauth_token=xxyyxx") 
    void getVenues(@Query("ll") String ll, 
       Callback<Object> cb); 
} 

chiamata RestAdapter

RestAdapter restAdapter = new RestAdapter.Builder() 
      .setEndpoint(ConfigConstants.VENUES_BASE_URL) 
      .build(); 

    Foursquare foursquare = restAdapter.create(Foursquare.class); 

foursquare.getVenues("30.26,-97.74", new Callback<Object>() { 
     @Override 
     public void success(Object o, Response response) { 
      Log.d(TAG, "Success!"); 
      // Parse response 
      GsonBuilder gsonBuilder = new GsonBuilder(); 
      Gson gson = gsonBuilder.create(); 
      JsonParser parser = new JsonParser(); 
      String response2 = gson.toJson(o); 
      JsonObject data = parser.parse(response2).getAsJsonObject(); 

      // Populate data model 
      MetaResponse metaResponse = gson.fromJson(data.get("meta"), MetaResponse.class); 
      VenuesExploreResponse myResponse = gson.fromJson(data.get("response"), VenuesExploreResponse.class);     

      // Store results from myResponse in List 
     } 

     @Override 
     public void failure(RetrofitError error) { 
      Log.d(TAG, "Failures!"); 
     } 
    }); 

Il problema attuale con l'implementazione richiamata sopra è che esso richiede più tempo (circa 1 secondo) che con Volley analizzare e mostrare i risultati. Il blocco GsonBuilder/Gson/JsonParser è esattamente lo stesso del mio metodo Volley onResponse (String response) tranne che per l'oggetto intermedio "response2", quindi il passaggio di bottiglia intermedio/extra è sicuramente il collo di bottiglia. Sto cercando suggerimenti su come implementare meglio l'analisi di Gson. Se questo potrebbe adattarsi meglio come una nuova/separata domanda, lo farò.

risposta

10

Così, come abbiamo già scoperto il problema era in ? ->& errore di battitura. Ma un'altra cosa da sottolineare è che Retrofit può accettare oggetti complessi come parametri di chiamata. Quindi verrà chiamato String.valueOf(object) per convertire l'oggetto in parametro Query/Path.

Nel tuo caso si potrebbe definire classe personalizzata come quella:

class LatLng { 
    private double lat; 
    private double lng; 

    ... 

    @Override public String toString() { 
    return String.format("%.1f,%.1f", lat, lng); 
    } 
} 

E refactoring del metodo endpoint così:

@GET("/explore?limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") 
void getVenues(@Query("ll") LatLng ll, Callback<String> cb); 

A proposito di analisi la risposta:

  • Mai creare Gson oggetti nel callback. È semplicemente troppo pesante. Utilizzare quello fornito a RestAdapter.
  • Perché mescoli JsonParser & Gson? Sono strumenti diversi per lo stesso problema.
  • Fare uso di meccanismi convertitore integrato di retrofit;)

Dalle parole in codice:

public class FoursquareResponse<T> { 
    private MetaResponse meta; 
    private T response; 
    // getters 
} 

Complessivamente:

@GET("/explore?limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") 
void getVenues(@Query("ll") LatLng ll, Callback<FoursquareResponse<VenuesExploreResponse>> cb); 

... 

foursquare.getVenues(LatLng.valueOf(30.26, -97.74), new Callback<FoursquareResponse<VenuesExploreResponse>>() { 
    @Override 
    public void success(FoursquareResponse<VenuesExploreResponse> r, Response response) { 
     MetaResponse metaResponse = r.getMeta; 
     VenuesExploreResponse myResponse = r.getResponse(); 

     // Store results from myResponse in List 
    } 

    @Override 
    public void failure(RetrofitError error) { 
     Log.d(TAG, "Failures!"); 
    } 
}); 
+0

Grazie per il suggerimento. Lo rifatterò sicuramente. Qualche suggerimento sulla parte parsing di Gson? Devo presentare una nuova domanda per questo? – cavega

+0

@cavega mi dispiace, non ho notato la terza nota alla prima volta. – colriot

+0

Grazie per la spiegazione dettagliata sull'uso delle funzionalità di analisi di Gson incorporate di Retrofit. Ho preso l'intero codice JsonParser/Gson da una risposta a una domanda specifica di Gson che ho fatto un po 'di tempo fa. Sto sicuramente facendo un tuffo nel codice di Retrofit. – cavega

0

Basta UrlEncode tuo virgola argomenti separati, comma =% 2

+2

Ret rofit codificherà automaticamente i valori della query. –

+0

@JakeWharton Mi chiedo se il problema potrebbe essere l'ordine in cui Retrofit ordina i parametri quando effettua la richiesta HTTP effettiva. Retrofit inserisce i parametri Query subito dopo l'url di base? O alla fine dell'URL completo?Attualmente sto ottenendo un 400 sul codice che ho postato. – cavega

+1

Aggiunge quelli dinamici alla fine dei parametri di query statici. Puoi attivare la registrazione per vedere l'intero URL in uscita. –

0

tenta di aggiungere tutte le query params (fisso e variabile) in ordine valido. intendo

@GET("/explore") 
Response getVenues(@Query("ll") ll, @Query("limit") limit, @Query("radius") radius, @Query("v") v, @Query("venuePhotos") venuePhotos, @Query("oauth_token") oauth_token); 

e avvolgere chiamata con funzione che hanno fissato params come costanti

+0

Sono stato in grado di ri-risolvere il mio codice 400 con il suggerimento @colriot, ma sì, stavo progettando di ridefinire l'interfaccia inserendo la maggior parte se non tutti i parametri come parametri di Query. Grazie per il feedback. – cavega

0

È possibile utilizzare @EncodedQuery:

@GET("/explore&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") 
void getVenues(@EncodedQuery("ll") LatLng ll, Callback<String> cb);