Дооснащение: Как указать в запросе параметры, разделенные запятыми?

Я пытаюсь реорганизовать свой код, чтобы использовать 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);

и оберните вызов функцией, у которой фиксированные параметры постоянны

Другие вопросы по тегам