fullMoon fullMoon - 6 months ago 44
JSON Question

JSON Response Using Retrofit on Android

I'm able to get JSON response using OkHttp3, and I want to use Retrofit to parse the response to get the name and the image from it. I looked into Retrofit website and some tutorials, but still the process not clear.

Here is my OkHttp3 code to get JSON response:

Request request = new Request.Builder().url(url).build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();

}

@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + responseHeaders.value(i));
}
System.out.println(response.body().string());
String jData = response.body().string();// I want to parse jData using Retrofit

}
});


The JSON response looks like this:

enter image description here

I want to get the name, id, and the image of each artist, any help is greatly appreciated.

UPDATE

I added Pojo classes one of them is Item class:

public class Item {

@SerializedName("external_urls")
@Expose
private ExternalUrls externalUrls;
@SerializedName("followers")
@Expose
private Followers followers;
@SerializedName("genres")
@Expose
private List<Object> genres = new ArrayList<Object>();
@SerializedName("href")
@Expose
private String href;
@SerializedName("id")
@Expose
private String id;
@SerializedName("images")
@Expose
private List<Object> images = new ArrayList<Object>();
@SerializedName("name")
@Expose
private String name;
@SerializedName("popularity")
@Expose
private Integer popularity;
@SerializedName("type")
@Expose
private String type;
@SerializedName("uri")
@Expose
private String uri;

/**
*
* @return
* The externalUrls
*/
public ExternalUrls getExternalUrls() {
return externalUrls;
}

/**
*
* @param externalUrls
* The external_urls
*/
public void setExternalUrls(ExternalUrls externalUrls) {
this.externalUrls = externalUrls;
}

/**
*
* @return
* The followers
*/
public Followers getFollowers() {
return followers;
}

/**
*
* @param followers
* The followers
*/
public void setFollowers(Followers followers) {
this.followers = followers;
}

/**
*
* @return
* The genres
*/
public List<Object> getGenres() {
return genres;
}

/**
*
* @param genres
* The genres
*/
public void setGenres(List<Object> genres) {
this.genres = genres;
}

/**
*
* @return
* The href
*/
public String getHref() {
return href;
}

/**
*
* @param href
* The href
*/
public void setHref(String href) {
this.href = href;
}

/**
*
* @return
* The id
*/
public String getId() {
return id;
}

/**
*
* @param id
* The id
*/
public void setId(String id) {
this.id = id;
}

/**
*
* @return
* The images
*/
public List<Object> getImages() {
return images;
}

/**
*
* @param images
* The images
*/
public void setImages(List<Object> images) {
this.images = images;
}

/**
*
* @return
* The name
*/
public String getName() {
return name;
}

/**
*
* @param name
* The name
*/
public void setName(String name) {
this.name = name;
}

/**
*
* @return
* The popularity
*/
public Integer getPopularity() {
return popularity;
}

/**
*
* @param popularity
* The popularity
*/
public void setPopularity(Integer popularity) {
this.popularity = popularity;
}

/**
*
* @return
* The type
*/
public String getType() {
return type;
}

/**
*
* @param type
* The type
*/
public void setType(String type) {
this.type = type;
}

/**
*
* @return
* The uri
*/
public String getUri() {
return uri;
}

/**
*
* @param uri
* The uri
*/
public void setUri(String uri) {
this.uri = uri;
}


}

Here how I'm using Retrofit in my activity:

private void loadJSON() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.spotify.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
final Artists_Interface request = retrofit.create(Artists_Interface.class);

Call<Item> call = request.getArtists();
call.enqueue(new Callback<Item>() {
@Override
public void onResponse(Call<Item> call, Response<Item> response) {
if(response.isSuccessful()){
Item artist = response.body();
System.out.println("THE NAME::::. : " + artist.getName());
}
else{
System.out.println(" :::. NOO RESPONSE .::: " );
}
}

@Override
public void onFailure(Call<Item> call, Throwable t) {
System.out.println("onFAIL::: " + t);
}
});


And here how the retrofit interface look like:

public interface Artists_Interface {

@GET("/v1/search?q=Beyonce&type=artist")
Call<Item> getArtists();


}

I get artist.getName() equals null. I need to get into name, id, and images that are inside "items" in JSON body and pass them to listView or recyclerView adapter

Answer

I appreciate all answers, thanks to everyone. I managed to solve the problem by putting pieces together since Retrofit has poor documentation, and some answers aren't detailed enough to be accepted. I wanted to extract data from JSON response from this link: https://api.spotify.com/v1/search?q=Beyonce&type=artist

Step1: Create a Pojo class to serialize the items in the response. Here we have "artists" array and inside it "href" string and "items" list, so as Aritra suggested, we can use http://www.jsonschema2pojo.org to generate the pojo classes. here how mine look like after some modification:

public class Data implements Serializable{

@SerializedName("artists")
Artists artists;

public Artists getArtists() {
    return artists;
}


public static class Artists {

    @SerializedName("href")
    private String href;

    @SerializedName("items")
    private List<Item> items;


    public String getHref(){
        return href;
    }

    public List<Item> getItems(){
        return items;
    }

}// Artists



public static class Item {
    // You have your item class here
    @SerializedName("external_urls")
    @Expose
    private ExternalUrls externalUrls;
    @SerializedName("followers")
    @Expose
    private Followers followers;
    @SerializedName("genres")
    @Expose
    private List<Object> genres = new ArrayList<Object>();
    @SerializedName("href")
    @Expose
    private String href;
    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("images")
    @Expose
    private List<Object> images = new ArrayList<Object>();
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("popularity")
    @Expose
    private Integer popularity;
    @SerializedName("type")
    @Expose
    private String type;
    @SerializedName("uri")
    @Expose
    private String uri;


    public Item() {
        name = "";
        id = "";
        images = new ArrayList<>();
    }


    /**
     * @return The externalUrls
     */
    public ExternalUrls getExternalUrls() {
        return externalUrls;
    }

    /**
     * @param externalUrls The external_urls
     */
    public void setExternalUrls(ExternalUrls externalUrls) {
        this.externalUrls = externalUrls;
    }

    /**
     * @return The followers
     */
    public Followers getFollowers() {
        return followers;
    }

    /**
     * @param followers The followers
     */
    public void setFollowers(Followers followers) {
        this.followers = followers;
    }

    /**
     * @return The genres
     */
    public List<Object> getGenres() {
        return genres;
    }

    /**
     * @param genres The genres
     */
    public void setGenres(List<Object> genres) {
        this.genres = genres;
    }

    /**
     * @return The href
     */
    public String getHref() {
        return href;
    }

    /**
     * @param href The href
     */
    public void setHref(String href) {
        this.href = href;
    }

    /**
     * @return The id
     */
    public String getId() {
        return id;
    }

    /**
     * @param id The id
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * @return The images
     */
    public List<Object> getImages() {
        return images;
    }

    /**
     * @param images The images
     */
    public void setImages(List<Object> images) {
        this.images = images;
    }

    /**
     * @return The name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name The name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return The popularity
     */
    public Integer getPopularity() {
        return popularity;
    }

    /**
     * @param popularity The popularity
     */
    public void setPopularity(Integer popularity) {
        this.popularity = popularity;
    }

    /**
     * @return The type
     */
    public String getType() {
        return type;
    }

    /**
     * @param type The type
     */
    public void setType(String type) {
        this.type = type;
    }

    /**
     * @return The uri
     */
    public String getUri() {
        return uri;
    }

    /**
     * @param uri The uri
     */
    public void setUri(String uri) {
        this.uri = uri;
    }

}// Item

}

So, the array "artists" represented as Artists class that contains href String and items list elements all serialized to match the JSON response. The items list is of type Item class, which contains many serialized elements, like id, name, images.. etc. all serialized to mach the JSON response.

Step2: The url is divided into 2 parts, a base and an endpoint. We use the base when we create Retrofit2 request. I'm calling this request from onCreate method:

private void loadJSON() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.spotify.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    final Artists_Interface request = retrofit.create(Artists_Interface.class);

    Call<Data> call = request.getArtists();
    call.enqueue(new Callback<Data>() {
        @Override
        public void onResponse(Call<Data> call, Response<Data> response) {

            if (response.isSuccessful()) {

                System.out.println(" Href ::::. : " + response.body().getArtists().getHref());

                List<Data.Item> items = response.body().getArtists().getItems();
                    for (int i = 0; i < items.size(); i++) {
                        adapter.addArtist(items.get(i));
                    }
            }
            else { System.out.println(" :::. NO RESPONSE .::: "); }

        }// End onResponse

        @Override
        public void onFailure(Call<Data> call, Throwable t) {
            System.out.println("onFAIL::: " + t);
        }
    });

Then, we use the endpoint in the Retrofit2 interface class:

public interface Artists_Interface {

@GET("/v1/search?q=Beyonce&type=artist")
Call<Data> getArtists();

}

Step3: Just assign the values we got from the response to the elements in our views. In step two I assigned the items list to the my recyclerView adapter, so here how my adapter look like:

public class Artists_Adapter extends RecyclerView.Adapter<Artists_Adapter.ViewHolder> {

private ArrayList<Data.Item> artists;

public Artists_Adapter(ArrayList<Data.Item> artists) {
    this.artists = artists;
}

@Override
public Artists_Adapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_artists, viewGroup, false);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(Artists_Adapter.ViewHolder viewHolder, int i) {

    viewHolder.name.setText(artists.get(i).getName());

}

@Override
public int getItemCount() {
    if(artists == null){
        return 0;
    }
    else {
        return artists.size();
    }
}

public void addArtist(Data.Item item){

    artists.add(item);

}

public class ViewHolder extends RecyclerView.ViewHolder{
    private TextView name ;
    private ImageView imageView;
    public ViewHolder(View view) {
        super(view);

        name = (TextView)view.findViewById(R.id.name);
        imageView = (ImageView) view.findViewById(R.id.image);

    }
}

}

And here how my onCreate() method look like:

    private RecyclerView recyclerView;
private ArrayList<Data.Item> data = new ArrayList<>();
private Artists_Adapter adapter;
static Context ctx;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_search);

    ctx = this;
    url = "https://api.spotify.com/v1/search?q=Beyonce&type=artist";

    loadJSON();
    initViews();


}// onCreate


private void initViews() {
    recyclerView = (RecyclerView) findViewById(R.id.card_recycler_view);
    recyclerView.setHasFixedSize(true);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(layoutManager);
    adapter = new Artists_Adapter(data);
    recyclerView.setAdapter(adapter);

}