0

I've managed to get it to work without a dynamic key. By following this tutorial with this json:

Currently, I'm using Retrofit and trying to get a response with dynamic keys. However, the response body is always null:

enter image description here

This is the response format:

{
    "dynamic1": {
        "cityID": "id1",
        "priceRange": 15
    },
    "dynamic2": {
        "cityID": "id2",
        "priceRange": 15
    }
}

In APIUtils.java

    public static CityService getCitiesService() {
        return RetrofitClient.getClient(BASE_URL).create(CityService.class);
    }

In CityService.java

public interface CityService {

    @GET("/SAGetStrollAwayCity")
    Call<CityResponse> getCities();

    @GET("/SAGetStrollAwayCity")
    Call<CityResponse> getCities(@Query("tagged") String tags);
}

In CityResponse.java:

public class CityResponse {
    /*@SerializedName("results")
    @Expose*/ // is this the correct way?
    private Map<String, CityDetails> city = new HashMap<>();

    public Map<String, CityDetails> getCity() {
        return city;
    }

    public void setCity(Map<String, CityDetails> elemDetails) {
        this.city = elemDetails;
    }

}

In CityDetails.java

public class CityDetails {

    @SerializedName("cityID")
    @Expose
    private String cityID;
    @SerializedName("priceRange")
    @Expose
    private Integer priceRange;

    public String getCityID() {
        return cityID;
    }

    public void setCityID(String cityID) {
        this.cityID = cityID;
    }

    public Integer getPriceRange() {
        return priceRange;
    }

    public void setPriceRange(Integer priceRange) {
        this.priceRange = priceRange;
    }

}

In HomeFragment.java

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_home, null);
        // 2nd api call
        mServiceCity = ApiUtils.getCitiesService();
        loadCities();

        return rootView;
}

public void loadCities() {
    mServiceCity.getCities().enqueue(new Callback<CityResponse>() {
        @Override
        public void onResponse(Call<CityResponse> call, Response<CityResponse> response) {
         // !!! WHY IS THE RESPONSE BODY EMPTY???
            if(response.isSuccessful()) {

//                    adapter.updateCities(response.body().getCity());

                Log.d("MainActivity", "posts loaded from API"+ response.body().getCity());
            }else {
                int statusCode  = response.code();
                // handle request errors depending on status code
            }
        }

        @Override
        public void onFailure(Call<CityResponse> call, Throwable t) {
            //showErrorMessage();
            Log.d("MainActivity", "error loading from API");

        }
    });
}
user1872384
  • 6,886
  • 11
  • 61
  • 103

1 Answers1

6

Personally I'd drop the CityResponse model and just work with Map<String, CityDetails>.

The retrofit interface can then be:

public interface CityService {

  @GET("/SAGetStrollAwayCity")
  Call<Map<String, CityDetails>> getCities();

  @GET("/SAGetStrollAwayCity")
  Call<Map<String, CityDetails>> getCities(@Query("tagged") String tags);
}

In your scenario, the response body is empty because CityResponse would map to a json like:

{
  "city": {
    "dynamic1": {
      "cityID": "id1",
      "priceRange": 15
    },
    "dynamic2": {
      "cityID": "id2",
      "priceRange": 15
    }
  }
}

However, you don't have a root element called city. The json itself can already be mapped to a java Map.

Hope this helps.

Fred
  • 16,367
  • 6
  • 50
  • 65