Retrofit / Gson помещает пустую модель в список <> - PullRequest
0 голосов
/ 03 февраля 2019

Я пытаюсь получить json с помощью дооснащения и gson из API http://api.themoviedb.org/3/movie/. Я в основном работаю, все работает нормально, но когда я вызываю дополнительную информацию в своей DetailsActivity, я обнаруживаю, что модели в моем массивеEmty.Это странно, потому что я получаю даже правильное количество объектов в массиве из API.Но когда я регистрирую значение из модели (например, Log.d (TAG, movieTrailers.get (0) .getName ()), приложение вылетает. С помощью оператора if я выясняю, что это значение равно нулю.

Это, например, API http://api.themoviedb.org/3/movie/297802/videos?api_key=. (К сожалению, мне не разрешено публиковать ключ API). Он содержит в jsonarray видео о фильме.

Это мой код:

Модель:

public class MovieTrailer {

    @SerializedName("key")
    private String key;
    @SerializedName("name")
    private String name;
    @SerializedName("type")
    private String type;

    public MovieTrailer(String key, String name, String type){
        this.key = key;
        this.name = name;
        this.type = type;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

Модель для списка:

public class TrailersList {
    @SerializedName("results")
    @Expose
    private List<MovieTrailer> trailers = null;

    public List<MovieTrailer> getTrailers() {
        return trailers;
    }

    public void setTrailers(List<MovieTrailer> trailers) {
        this.trailers = trailers;
    }
}

Адаптер:

public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoAdapterViewHolder> {

    private List<MovieTrailer> movieTrailers;

    private final  VideoOnClickHandler videoOnClickHandler;

    public interface VideoOnClickHandler{
        void onClick(MovieTrailer movieTrailer);
    }

    public VideoAdapter(VideoOnClickHandler onClickHandler) {videoOnClickHandler = onClickHandler;}

    public class VideoAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

        public final TextView videoTypeText;
        public final TextView videoNameText;

        public VideoAdapterViewHolder(View view){
            super(view);
            videoTypeText = (TextView) view.findViewById(R.id.tv_video_type);
            videoNameText = (TextView) view.findViewById(R.id.tv_video_name);
            view.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            int adapterPosition = getAdapterPosition();
            MovieTrailer movieTrailer = movieTrailers.get(adapterPosition);
            videoOnClickHandler.onClick(movieTrailer);
        }
    }

    @NonNull
    @Override
    public VideoAdapterViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        Context context = viewGroup.getContext();
        int gridItem = R.layout.movie_trailer;
        LayoutInflater inflater = LayoutInflater.from(context);
        boolean shouldAttachToParentImmediately = false;

        View view = inflater.inflate(gridItem, viewGroup,shouldAttachToParentImmediately);

        return new VideoAdapter.VideoAdapterViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull VideoAdapterViewHolder videoAdapterViewHolder, int i) {
        MovieTrailer movieTrailer = movieTrailers.get(i);
        videoAdapterViewHolder.videoTypeText.setText(movieTrailer.getType());
        videoAdapterViewHolder.videoNameText.setText(movieTrailer.getName());
    }

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

    //Function to set movieTrailers
    public void setMovieTrailerArray(List<MovieTrailer> trailerArrayToSet){
        movieTrailers = trailerArrayToSet;
        notifyDataSetChanged();
    }


}

Интерфейс:

public interface GetDataService {

    @GET("{path}?api_key=" + BuildConfig.API_KEY)
    Call<MoviesList> getAllMovies(@Path("path") String path);

    @GET("{movieId}/reviews?api_key=" + BuildConfig.API_KEY)
    Call<TrailersList> getAllTrailers(@Path("movieId") String movieId);

    @GET("{movieId}/videos?api_key=" + BuildConfig.API_KEY)
    Call<ReviewsList> getAllReviews(@Path("movieId") String movieId);
}

Экземпляр модификации:

public class RetrofitClientInstance {

    //Base URL for API request
    private static final String MOVIE_DATABASE_URL_POPULAR =
            "http://api.themoviedb.org/3/movie/";

    /**
     * Get Retrofit Instance
     */
    private static Retrofit getRetrofitInstance() {
        return new Retrofit.Builder()
                .baseUrl(MOVIE_DATABASE_URL_POPULAR)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    /**
     * Get API Service
     *
     * @return API Service
     */
    public static GetDataService getApiService() {
        return getRetrofitInstance().create(GetDataService.class);
    }
}

И метод из DetailsActivity:

private void loadMovieTrailers(String movieId){
        GetDataService api = RetrofitClientInstance.getApiService();
        Call<TrailersList> call = api.getAllTrailers(movieId);

        call.enqueue(new Callback<TrailersList>() {
            @Override
            public void onResponse(Call<TrailersList> call, Response<TrailersList> response) {
                if(response.isSuccessful()){
                    movieTrailers = response.body().getTrailers();
                    if(movieTrailers.get(0).getName() == null){
                        Log.d("MODEL", "Null");
                    }else {
                        Log.d("MODEL", "Not Null");
                    }

                    videoAdapter.setMovieTrailerArray(movieTrailers);
                }
            }

            @Override
            public void onFailure(Call<TrailersList> call, Throwable t) {
            }
        });
    }

У кого-то есть идея, где ошибка?

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

В вашем классе MovieTrailer аннотации @Expose для полей отсутствуют.Таким образом, Gson создает объекты, но не находит полей для ввода фактических данных.

Кстати.@SerializedFieldName требуется только в том случае, если имя поля в JSON отличается от имени поля в вашей модели.

0 голосов
/ 04 февраля 2019

Я думаю, что проблема в вашем классе интерфейса с этими методами,

@GET("{movieId}/reviews?api_key=" + BuildConfig.API_KEY)
Call<TrailersList> getAllTrailers(@Path("movieId") String movieId);

@GET("{movieId}/videos?api_key=" + BuildConfig.API_KEY)
Call<ReviewsList> getAllReviews(@Path("movieId") String movieId);

С {movieId}/reviews вы получите следующий ответ JSON,

{
  "id": 297761,
  "page": 1,
  "results": [
    {
      "id": "57a814dc9251415cfb00309a",
      "author": "Frank Ochieng",
      "content": "Summertime 2016 has not been very kind to DC Comics-based personalities looking to shine consistently like their big screen Marvel Comics counterparts.",
      "url": "https://www.themoviedb.org/review/57a814dc9251415cfb00309a"
    }
  ],
  "total_pages": 1,
  "total_results": 1
}

и {movieId}/videos возвращает,

{
  "id": 550,
  "results": [
    {
      "id": "533ec654c3a36854480003eb",
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "key": "SUXWAEX2jlg",
      "name": "Trailer 1",
      "site": "YouTube",
      "size": 720,
      "type": "Trailer"
    }
  ]
}

Итак, оба они возвращают почти тот же результат с JSONArray (results), заключенным в JSONObject.Ответ JSON верен, проблем вообще нет.

При анализе ответа JSON фабрике преобразователей Gson не удается найти эквивалентный класс POJO для ответа.Вы даже не получаете никаких ошибок, потому что оба возвращают один и тот же тип ответа.

Простым решением является изменение (взаимозамена) URL-адресов следующих методов.

@GET("{movieId}/videos?api_key=" + BuildConfig.API_KEY)   // change from reviews to videos
Call<TrailersList> getAllTrailers(@Path("movieId") String movieId);  

@GET("{movieId}/reviews?api_key=" + BuildConfig.API_KEY)   // change from videos to reviews
Call<ReviewsList> getAllReviews(@Path("movieId") String movieId);

Вот и все!

...