Retrofit: ¿Cómo especificar parámetros separados por comas en la solicitud?
Estoy tratando de refactorizar mi código para utilizar Retrofit (de Volley) para algunas llamadas API Foursquare, pero no han encontrado un ejemplo adecuado que muestra cómo especificar un parámetro de consulta que tiene 2 valores separados por una coma.
Mi URL base es la siguiente:
- Android Retrofit 2 Simple XML Converter
- Autentificación JWT de la firma de la firma del decodin del error
- Parse Dynamic Key Json String utilizando Retrofit
- Retrofit 2 RxJava - Gson - Deserialización "Global", tipo respuesta de cambio
- Cambiar ConnectionTimeout de Retrofit OkHttpClient en tiempo de ejecución
public static final String VENUES_BASE_URL = "https://api.foursquare.com/v2/venues";
El resto de mi url es como esto:
"?ll=40.7,50.2&limit=50&radius=25000&v=20140909&venuePhotos=1&oauth_token=xxyyxx";
Primera implementación para mi interfaz:
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); }
Y luego hizo la solicitud como esta:
RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(ConfigConstants.VENUES_BASE_URL) .build(); Fourquare fourquare = restAdapter.create(Fourquare.class); Response myResponse = fourquare.getVenues("50", "75");
Sin embargo, lo anterior me dio el siguiente error:
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.
2ª implementación (Después de ver algunas de las respuestas de SO que usan los parámetros de consulta NOTA: Una vez que descubro la ll ll llamada de parámetro tendremos el token como parámetro):
@GET("/explore&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") void getVenues(@Query("ll") String ll, Callback<String> cb);
Con la llamada real como esto:
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 la implementación anterior el método failure () siempre se llama, así que todavía hay algo mal con mi código. ¿Puede alguien dar algunas sugerencias sobre la manera correcta de implementar esta llamada? Estoy más seguro de que el problema es con el "ll?" parámetro.
Actualización: Después de activar el registro, esta es la URL final que recibo de 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
Parece que el servidor Foursquare no le gusta el? Ll parámetro al final de la url y debe ser colocado de forma explícita después de ../v2/venues/explore como que está funcionando bien cuando un lugar de la solicitud a través del navegador.
¿Hay alguna solución para evitar esta limitación de la API?
3ª puesta en práctica (9/17/14) Con la sugerencia de colriot pude resolver el código de respuesta de 400 que estaba recibiendo con mi implementación anterior. Todavía estoy teniendo un problema de velocidad con GSON por lo que buscan sugerencias sobre cómo solucionarlo. Específicamente, mi implementación de Retrofit tarda más en mostrar mis resultados en comparación con Volley, así que me pregunto si hay una mejor manera de implementar la devolución de llamada.
Interfaz Cuadrangular
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); }
Llamada 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!"); } });
El problema actual con la implementación de devolución de llamada anterior es que tarda más (aproximadamente 1 segundo) que con Volley para analizar y mostrar los resultados. El bloque GsonBuilder / Gson / JsonParser es exactamente el mismo que en mi método Volley onResponse (String response) excepto para ese objeto intermedio "response2", por lo que definitivamente este paso intermedio / extra es el cuello de botella. Estoy buscando sugerencias sobre cómo implementar mejor el análisis de Gson. Si esto puede encajar mejor como una pregunta nueva / separada lo haré.
- Retrofit 2.0 cómo imprimir la respuesta json completa?
- No se puede verificar la llamada de método de simulación desde el suscriptor de RxJava
- Retrofit 2.0 lanzando "IllegalArgumentException: los parámetros @Field solo se pueden usar con la codificación de formularios". ¿Cómo hacer la consulta correcta de la API y arreglarlo?
- Cómo manejar la paginación en retrofit
- HTTP GET con el cuerpo de la solicitud RETROFIT
- Error: tipos incompatibles: GsonConverterFactory no se puede convertir en Factory
- Android / RxJava Cómo encadenar las solicitudes de red y volver a intentarlo cuando falla
- RxJava + retrofit, obtenga una lista y agregue información adicional para cada artículo
Así que, como ya hemos descubierto el problema estaba en ?
-> &
typo. Pero una cosa más a mencionar es que Retrofit puede aceptar objetos complejos como parámetros de llamada. Entonces String.valueOf(object)
será llamado para convertir el objeto en Query / Path param.
En tu caso podrías definir clases personalizadas así:
class LatLng { private double lat; private double lng; ... @Override public String toString() { return String.format("%.1f,%.1f", lat, lng); } }
Y refactorice su método de punto final de esa manera:
@GET("/explore?limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") void getVenues(@Query("ll") LatLng ll, Callback<String> cb);
Acerca de analizar la respuesta:
- Nunca cree objetos
Gson
directamente en la devolución de llamada. Es simplemente demasiado pesado. Utilice el que usted proporciona aRestAdapter
. - ¿Por qué mezclas
JsonParser
yGson
? Son herramientas diferentes para básicamente el mismo problema. - Hacer uso del mecanismo de conversión incorporado de Retrofit;)
De palabras a código:
public class FoursquareResponse<T> { private MetaResponse meta; private T response; // getters }
En total:
@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!"); } });
Sólo urlencode sus argumentos separados por coma, coma =% 2
Intente agregar todos los parámetros de consulta (fijos y variables) en orden válido. quiero decir
@GET("/explore") Response getVenues(@Query("ll") ll, @Query("limit") limit, @Query("radius") radius, @Query("v") v, @Query("venuePhotos") venuePhotos, @Query("oauth_token") oauth_token);
Y wrap llamada con función que tienen params fijos como constante
Puede utilizar @EncodedQuery
:
@GET("/explore&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx") void getVenues(@EncodedQuery("ll") LatLng ll, Callback<String> cb);
- Spinner muestra como diálogo
- Es tener que pasar el contexto a la mayoría de las clases un signo de mal diseño?