Дооснащение: Как указать в запросе параметры, разделенные запятыми?
Я пытаюсь реорганизовать свой код, чтобы использовать Retrofit (из Volley) для некоторых вызовов API Foursquare, но не нашел подходящего примера, показывающего, как указать параметр запроса, в котором 2 значения разделены запятой.
Моя базовая ссылка следующая:
public static final String VENUES_BASE_URL = "https://api.foursquare.com/v2/venues";
Остальная часть моего URL выглядит так:
"?ll=40.7,50.2&limit=50&radius=25000&v=20140909&venuePhotos=1&oauth_token=xxyyxx";
1-я реализация для моего интерфейса:
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);
}
А потом сделал запрос вот так:
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(ConfigConstants.VENUES_BASE_URL)
.build();
Fourquare fourquare = restAdapter.create(Fourquare.class);
Response myResponse = fourquare.getVenues("50", "75");
Однако вышесказанное дало мне следующую ошибку:
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-я реализация (После просмотра некоторых ответов SO, в которых используются параметры запроса. ПРИМЕЧАНИЕ. После того, как я выясню вызов параметра ll?, Я получу токен в качестве параметра):
@GET("/explore&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx")
void getVenues(@Query("ll") String ll,
Callback<String> cb);
С фактическим вызовом, как это:
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!");
}
});
В описанной выше реализации метод error () вызывается всегда, поэтому в моем коде все еще что-то не так. Может кто-нибудь дать несколько советов, как правильно осуществить этот вызов? Я уверен, что проблема с "ll?" параметр.
Обновление: после включения регистрации это последний URL, который я получаю от 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
Похоже, серверу Foursquare не нравится параметр ll в конце URL-адреса, и он должен быть явно размещен сразу после../v2/venues/explore, так как он работает нормально, когда отправляет запрос через браузер.
Какие-нибудь решения, чтобы обойти это ограничение от API?
3-я реализация (17.09.14) С предложением colriot мне удалось разрешить код ответа 400, который я получал с моей предыдущей реализацией. У меня все еще есть проблема с быстродействием GSON, поэтому я ищу предложения о том, как это исправить. В частности, моя реализация Retrofit требует больше времени для отображения моих результатов по сравнению с Volley, поэтому мне интересно, есть ли лучший способ реализовать обратный вызов.
Интерфейс 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);
}
Перезапуск вызова
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!");
}
});
В настоящее время проблема с вышеупомянутой реализацией обратного вызова заключается в том, что для анализа и отображения результатов требуется больше времени (около 1 секунды), чем при использовании Volley. Блок GsonBuilder/Gson/JsonParser точно такой же, как и в моем методе Volley onResponse(String response), за исключением этого промежуточного объекта response2, поэтому наиболее определенно этот промежуточный / дополнительный шаг является узким местом. Я ищу предложения о том, как лучше реализовать разбор Gson. Если это будет лучше, чем новый / отдельный вопрос, я сделаю это.
4 ответа
Итак, как мы уже узнали, проблема была в ?
-> &
опечатка. Но следует упомянуть еще одну вещь: Retrofit может принимать сложные объекты в качестве параметров вызова. затем String.valueOf(object)
будет вызван для преобразования объекта в параметр Query/Path.
В вашем случае вы можете определить пользовательский класс следующим образом:
class LatLng {
private double lat;
private double lng;
...
@Override public String toString() {
return String.format("%.1f,%.1f", lat, lng);
}
}
И рефакторинг вашего метода конечной точки так:
@GET("/explore?limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx")
void getVenues(@Query("ll") LatLng ll, Callback<String> cb);
О разборе ответа:
- Никогда не создавай
Gson
объекты прямо в обратном вызове. Это просто слишком тяжеловес. Используйте тот, который вы предоставляетеRestAdapter
, - Почему вы смешиваете
JsonParser
&Gson
? Это разные инструменты для решения одной и той же проблемы. - Используйте встроенный конвертерный механизм Retrofit;)
От слов к коду:
public class FoursquareResponse<T> {
private MetaResponse meta;
private T response;
// getters
}
Итого:
@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!");
}
});
Если вы используете котлин и у вас есть var items: List<String>
это должно быть параметром запроса.
Используйте этот метод для формирования строки:
fun itemsString(items: List<String>) = items.joinToString(separator = ",")
Ваш URL-запрос должен быть таким:
@Query(value = "items", encoded = true) String items
Ты можешь использовать @EncodedQuery
:
@GET("/explore&limit=50&radius=25000&v=20140905&venuePhotos=1&oauth_token=xxyyxx")
void getVenues(@EncodedQuery("ll") LatLng ll, Callback<String> cb);
Просто urlencode аргументов, разделенных запятыми, запятая = %2
Попробуйте добавить все параметры запроса (фиксированные и переменные) в правильном порядке. Я имею в виду
@GET("/explore")
Response getVenues(@Query("ll") ll, @Query("limit") limit, @Query("radius") radius, @Query("v") v, @Query("venuePhotos") venuePhotos, @Query("oauth_token") oauth_token);
и оберните вызов функцией, у которой фиксированные параметры постоянны