Ответ JSON с использованием модификации на Android

Я могу получить ответ JSON, используя OkHttp3, и я хочу использовать Retrofit для анализа ответа, чтобы получить от него имя и изображение. Я просмотрел веб-сайт Retrofit и несколько руководств, но процесс все еще не ясен.

Вот мой код OkHttp3 для получения ответа JSON:

 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

        }
    });

Ответ JSON выглядит так:

введите здесь описание изображения

Я хочу получить имя, идентификатор и изображение каждого художника, любая помощь очень ценится.

ОБНОВЛЕНИЕ

Я добавил классы Pojo, один из них - класс Item:

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;
}

}

Вот как я использую Retrofit в своей деятельности:

    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);
        }
    });

А вот как выглядит модифицированный интерфейс:

public interface Artists_Interface {

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

}

Я получаю artist.getName() равным нулю. Мне нужно получить имя, идентификатор и изображения, которые находятся внутри «элементов» в теле JSON, и передать их адаптеру listView или recyclerView.


person fullmoon    schedule 02.06.2016    source источник
comment
Относится ли класс Response к пакету дооснащения?   -  person Obscure Geek    schedule 02.06.2016
comment
Это ответ OkHttp3   -  person fullmoon    schedule 02.06.2016
comment
Так в чем проблема? У вас есть JSON, просто проанализируйте его вручную или используйте GSON для его анализа.   -  person Rohan Kandwal    schedule 02.06.2016
comment
Мне нужно использовать Retrofit для извлечения данных   -  person fullmoon    schedule 02.06.2016


Ответы (4)


Это не правильно,

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

Вы пытаетесь найти имя, идентификатор и т. д. в заголовках, хотя информация находится в теле ответа.

Просто создайте POJO для своей модели данных и извлеките информацию в модель из объекта ответа. Затем вы можете просто использовать геттеры и сеттеры для доступа к вашим необходимым данным.

ОБНОВЛЕНИЕ

Вы можете легко создать свой POJO, используя этот сайт, http://www.jsonschema2pojo.org. Просто скопируйте и вставьте свой JSON, и он мгновенно сгенерирует для вас POJO.

Теперь, когда у вас есть POJO, вы можете либо вручную проанализировать его, либо использовать библиотеку GSON или Jackson, чтобы сделать это легко.

ОБНОВЛЕНИЕ 2

Ошибка здесь совершенно очевидна,

Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1

В нем четко указано, что синтаксический анализатор ожидал массив, но нашел объект в фактическом JSON.

См. фактический JSON, он начинается с объекта, а не массива, так почему вы используете List здесь,

Call<List<Item>> getArtists();

Если вы посмотрите на свой JSON, вы увидите, что он начинается с объекта, внутри которого у вас есть другой объект с ключом «исполнители», а затем у вас есть список элементов с ключевыми «элементами».

Вам также не нужно было ничего делать вручную. www.jsonschema2pojo.org сгенерировал бы все для вас, вам просто нужно было включить их.

Я не понимаю, почему вы включили список вместо объекта.

ОБНОВЛЕНИЕ 3

Добытчики, простые добытчики.

Предположим, у вас есть это, предположим.

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
    }
}

Теперь сделай это,

Call<Data> getArtists();

и чтобы получить предметы,

data.getArtists().getItemList();

Теперь ясно?

person Aritra Roy    schedule 02.06.2016
comment
Что меня смущает, класс модели будет содержать что именно, массив для элементов или просто имя, идентификатор, объекты изображения? Буду признателен, если вы можете показать фрагмент - person fullmoon; 02.06.2016
comment
Если это решило вашу проблему, рассмотрите возможность принятия ответа или дайте мне знать, если вам нужна помощь. - person Aritra Roy; 02.06.2016
comment
Спасибо. Он сгенерировал множество классов для всего в ответе. Должен ли я включать их все в проект или только те, которые мне нужны. - person fullmoon; 02.06.2016
comment
Просто включите класс, который вам нужен. - person Aritra Roy; 02.06.2016
comment
Я обновил свой вопрос с вашим предложением, я ценю это, если вы можете взглянуть на него. - person fullmoon; 02.06.2016
comment
Спасибо вам за помощь. Я добавил все классы, созданные для меня www.jsonschema2pojo.org, изменил код и удалил список. Мне нужен список, потому что мне нужны элементы name, id и images внутри элементов в теле сына, извините, я новичок в Retrofit. Теперь он не жаловался на BEGIN_ARRAY, но я получаю null, когда пытаюсь получить имя из ответа. Я изменил обновление для вопроса, если хотите посмотреть. - person fullmoon; 03.06.2016
comment
Пожалуйста, не копируйте и не вставляйте вслепую. Попытайтесь понять проблему. Вы опять ошиблись. Прочитайте ОБНОВЛЕНИЕ 2 моего ответа еще раз, ответ лежит там же. Это сэкономит вам много времени и позволит быстро выполнить свою работу. - person Aritra Roy; 03.06.2016
comment
Вы сказали. Если вы посмотрите на свой JSON, вы увидите, что он начинается с объекта, внутри которого у вас есть другой объект с ключевыми исполнителями, а затем у вас есть список элементов с ключевыми элементами. Круто, а как теперь попасть в этот список? Если вы покажете реальный код, будет лучше, потому что таким образом могут возникнуть ошибки при попытке интерпретировать то, что вы имеете в виду. - person fullmoon; 03.06.2016
comment
Проверьте мой обновленный ответ. Если это поможет вам хоть немного, вы должны отметить ответ как принятый. Я изо всех сил старался, чтобы вы поняли это. Спасибо. - person Aritra Roy; 03.06.2016

Я ценю все ответы, спасибо всем. Мне удалось решить проблему, собрав части вместе, поскольку у Retrofit плохая документация, а некоторые ответы недостаточно подробны, чтобы их можно было принять. Я хотел извлечь данные из ответа JSON по этой ссылке: https://api.spotify.com/v1/search?q=Beyonce&type=artist

Шаг 1. Создайте класс Pojo для десериализации элементов в ответе. десериализация в основном означает, что в этом ответе JSON у нас есть массив «исполнители», а внутри него строка «href» и список «элементов», поэтому, как предложила Аритра, мы можем использовать http://www.jsonschema2pojo.org для создания классов pojo, которые будут десериализовать эти элементы для нас. Вот как выглядит мой после некоторой модификации:

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

}

Итак, массив «исполнители», представленный как класс Artists, который содержит href String и элементы списка элементов, все сериализованы в соответствии с ответом JSON. Список элементов имеет тип класса Item, который содержит множество сериализованных элементов, таких как идентификатор, имя, изображения и т. д., все сериализованные для обработки ответа JSON.

Шаг 2. URL-адрес делится на 2 части: базовую и конечную. Мы используем базу, когда создаем запрос Retrofit2. Я вызываю этот запрос из метода onCreate:

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);
        }
    });

Затем мы используем конечную точку в классе интерфейса Retrofit2:

public interface Artists_Interface {

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

}

Шаг 3. Просто назначьте значения, полученные в результате ответа, элементам в представлениях. На втором шаге я назначил список элементов моему адаптеру recyclerView, вот как выглядит мой адаптер:

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);

    }
}

}

А вот как выглядит мой метод onCreate():

    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);

}
person fullmoon    schedule 04.06.2016

Вы можете использовать Android JSONObject. класс как:

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

После создания объекта вы можете использовать метод .get() для извлечения необходимых полей, как в обычном формате JSON.

person Obscure Geek    schedule 02.06.2016
comment
Спасибо за ваше предложение, но мне нужно использовать Retrofit для извлечения данных. - person fullmoon; 02.06.2016
comment
Что именно вы подразумеваете под use Retrofit to extract the data? Retrofit просто даст вам ответные данные, верно? Вам нужно использовать другой класс, например JSONObject, или преобразовать его в POJO, используя Gson для доступа к данным. - person Obscure Geek; 02.06.2016
comment
Я немного запутался в том, как okhttp3 можно использовать вместе с Retrofit, я обновил свой вопрос, посмотрите, можете ли вы мне что-нибудь предложить, спасибо - person fullmoon; 02.06.2016

Простая демонстрация доступна здесь. через это

person Basi    schedule 02.06.2016
comment
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. - person greg-449; 02.06.2016