简体   繁体   中英

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:

在此处输入图片说明

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

This is wrong,

Headers responseHeaders = response.headers();
            for (int i = 0, size = responseHeaders.size(); i < size; i++) {
                System.out.println(responseHeaders.name(i) + responseHeaders.value(i));
            }

You are trying to find the name, id, etc. data in the headers, while the information is in the body of the response.

Just create a POJO for your data model and retrieve the information into the model from the response object. Then you can just simply use getters and setters to access your required data.

UPDATE

You can create your POJO easily using this site, http://www.jsonschema2pojo.org . Just copy and paste your JSON and it will generate the POJOs for you instantly.

Now once you have the POJO, you can either manually parse it or use GSON or Jackson library to do it easily.

UPDATE 2

The error is quite self-explanatory here,

Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1

It clearly states that the parser expected an array but found an object in the actual JSON.

See the actual JSON, it starts with an object and not an array , so why are you using List here,

Call<List<Item>> getArtists();

If you look at your JSON you can see that it starts with an object, inside which you have another object with key "artists" and then you have a list of items with key "items".

You also didn't need to do anything manually. www.jsonschema2pojo.org would have generated everything for you, you just had to include them.

I don't understand why you have included a List instead of an object.

UPDATE 3

Getters man, simple getters.

Suppose you have this, suppose .

class Data {

    Artists artists;

    Artists getArtists() {
        return artists;
    }

    class Artists {
        List<Item> list;

        List<Item> getItemList(){
            return  list;
        }
    }

    class Item {
        // You have your item class here
    }
}

Now do this,

Call<Data> getArtists();

and to get items,

data.getArtists().getItemList();

Is that now clear?

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 deserialize the items in the response. deserializing basically means that in this JSON response, 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 that will deserialize these items for us. 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);

}

You can use the android JSONObject class like:

JSONObject json = new JSONObject(response.body().string());

After creating the object you can use the .get() method to extract the required fields like a normal JSON.

有简单的演示在这里 ,请通过它去

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM