2017-04-23 38 views
-1

我正在使用Retrofit库来解析现在播放电影类别的TMDB API的Json响应,并且想要在RecyclerView中显示结果。Retrofit库提供null Json响应

钍生对此我从API获取JSON是

{ 
    "page": 1, 
    "results": [ 
    { 
     "poster_path": "\/tWqifoYuwLETmmasnGHO7xBjEtt.jpg", 
     "adult": false, 
     "overview": "A live-action adaptation of Disney's version of the classic 'Beauty and the Beast' tale of a cursed prince and a beautiful young woman who helps him break the spell.", 
     "release_date": "2017-03-16", 
     "genre_ids": [ 
     14, 
     10749 
     ], 
     "id": 321612, 
     "original_title": "Beauty and the Beast", 
     "original_language": "en", 
     "title": "Beauty and the Beast", 
     "backdrop_path": "\/6aUWe0GSl69wMTSWWexsorMIvwU.jpg", 
     "popularity": 147.254531, 
     "vote_count": 1938, 
     "video": false, 
     "vote_average": 6.9 
    }, 
    { 
     "poster_path": "\/unPB1iyEeTBcKiLg8W083rlViFH.jpg", 
     "adult": false, 
     "overview": "A story about how a new baby's arrival impacts a family, told from the point of view of a delightfully unreliable narrator, a wildly imaginative 7 year old named Tim.", 
     "release_date": "2017-03-23", 
     "genre_ids": [ 
     16, 
     35, 
     10751 
     ], 
     "id": 295693, 
     "original_title": "The Boss Baby", 
     "original_language": "en", 
     "title": "The Boss Baby", 
     "backdrop_path": "\/bTFeSwh07oX99ofpDI4O2WkiFJ.jpg", 
     "popularity": 138.856227, 
     "vote_count": 649, 
     "video": false, 
     "vote_average": 5.7 
    }, 

我所创建的模型类是Movie.java

package com.example.vikas.movie.model; 

/** 
* Created by vikas on 22/4/17 
*/ 
import com.google.gson.annotations.SerializedName; 

import java.util.ArrayList; 
import java.util.List; 
public class Movie 
{ 
    @SerializedName("poster_path") 
    private String posterPath; 
    @SerializedName("adult") 
    private boolean adult; 
    @SerializedName("overview") 
    private String overview; 
    @SerializedName("realease_date") 
    private String releaseDate; 
    @SerializedName("genre_ids") 
    private List<Integer> genreIds=new ArrayList<Integer>(); 
    @SerializedName("id") 
    private int id; 
    @SerializedName("original_title") 
    private String originalTitle; 
    @SerializedName("original_language") 
    private String original_language; 
    @SerializedName("title") 
    private String title; 
    @SerializedName("backdrop_path") 
    private String backdrop_path; 
    @SerializedName("popularity") 
    private Double popularity; 
    @SerializedName("vote_count") 
    private int vote_count; 
    @SerializedName("vedeo") 
    private boolean vedeo; 
    @SerializedName("vote_average") 
    private Double vote_average; 


    public Movie(String posterPath, boolean adult, String overview, String releaseDate, List<Integer> genreIds, Integer id, 
       String originalTitle, String original_language, String title, String backdrop_path, Double popularity, 
       Integer vote_count, Boolean vedeo, Double vote_average) { 
     this.posterPath = posterPath; 
     this.adult = adult; 
     this.overview = overview; 
     this.releaseDate = releaseDate; 
     this.genreIds = genreIds; 
     this.id = id; 
     this.originalTitle = originalTitle; 
     this.original_language = original_language; 
     this.title = title; 
     this.backdrop_path = backdrop_path; 
     this.popularity = popularity; 
     this.vote_count = vote_count; 
     this.vedeo = vedeo; 
     this.vote_average = vote_average; 
    } 

    public String getPosterPath() { 
     return posterPath; 
    } 

    public void setPosterPath(String posterPath) { 
     this.posterPath = posterPath; 
    } 

    public boolean isAdult() { 
     return adult; 
    } 

    public void setAdult(boolean adult) { 
     this.adult = adult; 
    } 

    public String getOverview() { 
     return overview; 
    } 

    public void setOverview(String overview) { 
     this.overview = overview; 
    } 

    public String getReleaseDate() { 
     return releaseDate; 
    } 

    public void setReleaseDate(String releaseDate) { 
     this.releaseDate = releaseDate; 
    } 

    public List<Integer> getGenreIds() { 
     return genreIds; 
    } 

    public void setGenreIds(List<Integer> genreIds) { 
     this.genreIds = genreIds; 
    } 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public String getOriginalTitle() { 
     return originalTitle; 
    } 

    public void setOriginalTitle(String originalTitle) { 
     this.originalTitle = originalTitle; 
    } 

    public String getOriginalLanguage() { 
     return original_language; 
    } 

    public void setOriginalLanguage(String original_language) { 
     this.original_language = original_language; 
    } 

    public String getTitle() { 
     return title; 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 

    public String getBackdropPath() { 
     return backdrop_path; 
    } 

    public void setBackdropPath(String backdropPath) { 
     this.backdrop_path = backdropPath; 
    } 

    public Double getPopularity() { 
     return popularity; 
    } 

    public void setPopularity(Double popularity) { 
     this.popularity = popularity; 
    } 

    public Integer getvote_count() { 
     return vote_count; 
    } 

    public void setVoteCount(Integer voteCount) { 
     this.vote_count = voteCount; 
    } 

    public Boolean getVedeo() { 
     return vedeo; 
    } 

    public void setVedeo(Boolean vedeo) { 
     this.vedeo = vedeo; 
    } 

    public Double getvote_average() { 
     return vote_average; 
    } 

    public void setVoteAverage(Double vote_average) { 
     this.vote_average = vote_average; 
    } 
} 

MovieResponse.java

package com.example.vikas.movie.model; 

/** 
* Created by vikas on 22/4/17. 
*/ 
import com.google.gson.annotations.SerializedName; 
import java.util.List; 
public class MoviesResponse 
{ 
    @SerializedName("page") 
    private int page; 
    @SerializedName("results") 
    private List<Movie>results; 
    @SerializedName("total_results") 
    private int totalResults; 
    @SerializedName("total_pages") 
    private int totalPages; 
    public int getPage() { 
     return page; 
    } 

    public void setPage(int page) { 
     this.page = page; 
    } 

    public List<Movie> getResults() { 
     return results; 
    } 

    public void setResults(List<Movie> results) { 
     this.results = results; 
    } 

    public int getTotalResults() { 
     return totalResults; 
    } 

    public void setTotalResults(int totalResults) { 
     this.totalResults = totalResults; 
    } 

    public int getTotalPages() { 
     return totalPages; 
    } 

    public void setTotalPages(int totalPages) { 
     this.totalPages = totalPages; 
    } 




} 

现在使下面的API调用是我编写的用于生成URL并创建实例的类我正在使用这些类来生成URL并调用API。

ApiClient.java package com.example.vikas.movi​​e.rest;

/** 
* Created by vikas on 22/4/17. 
*/ 
import retrofit2.Retrofit; 
import retrofit2.converter.gson.GsonConverterFactory; 
public class ApiClient 
{ 
    public static final String URL="http://api.themoviedb.org/3/"; 
    private static Retrofit retrofit=null; 

    public static Retrofit getClient() 
    { 
     if(retrofit==null) 
     { 
      retrofit= new Retrofit.Builder()//netsed class of Retrofit used to create a new instance of retrofit class 
        .baseUrl(URL)//loaded the base URL which will be used later for all api calls 
        .addConverterFactory(GsonConverterFactory.create())//added converter factory for 
        // serialization and desserialization of objects 

        .build();//created the retrofit instance with configured values 

     } 
     return retrofit; 
    } 

} 

ApiInterface.java

package com.example.vikas.movie.rest; 

/** 
* Created by vikas on 23/4/17. 
*/ 
import com.example.vikas.movie.model.MoviesResponse; 
import retrofit2.Call; 
import retrofit2.http.GET; 
import retrofit2.http.Path; 
import retrofit2.http.Query; 
// to define endpoints of a URL we will use special retrofit annotations. we have used Get annotation in 
// to get information from the API and the parameters os this method are @Query,@Path, 
public interface ApiInterface 
{ 
    @GET("movie/now-playing") 
    Call<MoviesResponse> getNowPlayingMovies(@Query("api_key") String apikey); 
    //return value is alwayays a parameterized call<T> oject whose paremeter is generic so we can have 
    @GET("movie/{id}") 
    Call<MoviesResponse> getMovieDetails(@Path("id") int id, @Query("api_key") String apiKey); 
} 


// so using this we will generate the following URL 
//http://api.themoviedb.org/3/movie/now-playing?api_key=Xxxx 

,现在我显示结果RecyclerView所以对于Dapter类是

MovieAdapter.java

package com.example.vikas.movie.adapter; 

/** 
* Created by vikas on 23/4/17. 
*/ 
import android.content.Context; 
import android.support.v7.widget.RecyclerView; 
import android.text.TextUtils; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.ImageView; 
import android.widget.LinearLayout; 
import android.widget.RelativeLayout; 
import android.widget.TextView; 

import com.bumptech.glide.Glide; 
import com.bumptech.glide.load.engine.DiskCacheStrategy; 
import com.example.vikas.movie.R; 
import com.example.vikas.movie.helper.CircleTransformation; 
import com.example.vikas.movie.model.Movie; 

import java.util.List; 
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> { 

    private List<Movie> movies; 
    private int rowLayout; 
    private Context context; 


    public static class MovieViewHolder extends RecyclerView.ViewHolder { 
     RelativeLayout moviesLayout; 
     TextView movieTitle; 
     TextView data; 
     TextView movieDescription; 
     TextView rating; 


     public MovieViewHolder(View v) { 
      super(v); 
      moviesLayout = (RelativeLayout) v.findViewById(R.id.movie_layout); 
      movieTitle = (TextView) v.findViewById(R.id.title); 
      data = (TextView) v.findViewById(R.id.subtitle); 
      movieDescription = (TextView) v.findViewById(R.id.description); 
      rating = (TextView) v.findViewById(R.id.rating); 
     } 
    } 

    public MovieAdapter(List<Movie> movies, int rowLayout, Context context) { 
     this.movies = movies; 
     this.rowLayout = rowLayout; 
     this.context = context; 
    } 

    @Override 
    public MovieAdapter.MovieViewHolder onCreateViewHolder(ViewGroup parent, 
                  int viewType) { 
     View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false); 
     return new MovieViewHolder(view); 
    } 


    @Override 
    public void onBindViewHolder(MovieViewHolder holder, final int position) { 
     holder.movieTitle.setText(movies.get(position).getTitle()); 
     holder.data.setText(movies.get(position).getReleaseDate()); 
     holder.movieDescription.setText(movies.get(position).getOverview()); 
     holder.rating.setText(movies.get(position).getvote_average().toString()); 
    } 

    @Override 
    public int getItemCount() { 
     return movies.size(); 
    } 
} 

现在MainActivity类别其中我正在调用API并获取结果并将结果提供给适配器[R

MainActivity.java

package com.example.vikas.movie; 

import android.support.design.widget.CoordinatorLayout; 
import android.support.design.widget.Snackbar; 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.support.v7.widget.DefaultItemAnimator; 
import android.support.v7.widget.LinearLayoutManager; 
import android.support.v7.widget.RecyclerView; 
import android.util.Log; 


import com.example.vikas.movie.adapter.MovieAdapter; 
import com.example.vikas.movie.model.Movie; 
import com.example.vikas.movie.model.MoviesResponse; 
import com.example.vikas.movie.rest.ApiClient; 
import com.example.vikas.movie.rest.ApiInterface; 

import java.util.ArrayList; 
import java.util.List; 

import retrofit2.Call; 
import retrofit2.Callback; 
import retrofit2.Response; 

public class MainActivity extends AppCompatActivity 
{ 

    private static final String TAG=MainActivity.class.getSimpleName(); 
    //get which got from web API 
    private final static String API_KEY="Xxxxxx"; 
    private CoordinatorLayout coordinatorLayout; 
    private MovieAdapter movieAdapter; 
    private RecyclerView recyclerView; 
    private List<Movie> movieList = new ArrayList<>(); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     coordinatorLayout=(CoordinatorLayout)findViewById(R.id.coordinate_layout); 

     if(API_KEY.isEmpty()) 
     { 
      Snackbar snackbar = Snackbar 
        .make(coordinatorLayout, "Please Enter The key", Snackbar.LENGTH_LONG); 

      snackbar.show(); 
      return; 
     } 
     recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 
     recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext())); 
     recyclerView.setItemAnimator(new DefaultItemAnimator()); 
     recyclerView.setAdapter(new MovieAdapter(movieList, R.layout.recyclerview_item_movie, getApplicationContext())); 


     ApiInterface apiInterface= ApiClient.getClient().create(ApiInterface.class); 
     Call<MoviesResponse> call= apiInterface.getNowPlayingMovies(API_KEY); 
     call.enqueue(new Callback<MoviesResponse>() 
     { 
      @Override 
      public void onResponse(Call<MoviesResponse> call, Response<MoviesResponse> response) 
      { 
       Log.d(TAG, "Number of movies received: " + movieList.size()); 
       int statusCode=response.code(); 
       movieList= response.body().getResults(); 
       movieAdapter.notifyDataSetChanged(); 


      } 

      @Override 
      public void onFailure(Call<MoviesResponse> call, Throwable t) 
      { 
       Snackbar snackbar = Snackbar 
         .make(coordinatorLayout, "Please Check your Internet Connection", Snackbar.LENGTH_LONG); 

       snackbar.show(); 
       Log.e(TAG, t.toString()); 

      } 
     }); 

    } 
} 

但是当我运行这段代码,我得到这个错误的logcat

04-23 23:32:32.529 30506-30506/com.example.vikas.movie E/AndroidRuntime: FATAL EXCEPTION: main 
                    Process: com.example.vikas.movie, PID: 30506 
                    java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.vikas.movie.adapter.MovieAdapter.notifyDataSetChanged()' on a null object reference 
                     at com.example.vikas.movie.MainActivity$1.onResponse(MainActivity.java:69) 
                     at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68) 
                     at android.os.Handler.handleCallback(Handler.java:739) 
                     at android.os.Handler.dispatchMessage(Handler.java:95) 
                     at android.os.Looper.loop(Looper.java:148) 
                     at android.app.ActivityThread.main(ActivityThread.java:5417) 
                     at java.lang.reflect.Method.invoke(Native Method) 
                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

所以我现在应该做些什么来运行这段代码并获取结果成功的显示结果,它不会返回null

这个问题是不同的,因为首先我是不是能够不给正确的URL

+0

你总是固定一个NullPointerException以同样的方式...初始化对象,你的堆栈跟踪指向 –

回答

0

首先你的网址是错的。它应该是

http://api.themoviedb.org/3/movie/now_playing?api_key=ddfffa28b4ace50cacf67274370469a1 

通知终点电影/ now_playing的代替电影/现在扮演

这是记录在https://developers.themoviedb.org/3/movies/get-now-playing

你也可以在你得到的名单大小获得回复并初始化列表

首先这个

movieList= response.body().getResults(); 

然后

Log.d(TAG, "Number of movies received: " + movieList.size()); 

EDIT1:

你有这样的

recyclerView.setAdapter(new MovieAdapter(movieList, R.layout.recyclerview_item_movie, getApplicationContext())); 

你永远不会初始化,当你调用notifyDataSetChanged(),为空。

将其更改为

movieAdapter = new MovieAdapter(movieList, R.layout.recyclerview_item_movie, getApplicationContext()); 

然后

recyclerView.setAdapter(movieAdapter); 

注意得到getApplicationContext()可能不是有用的是与UI大多数情况下。喜欢活动上下文。

编辑2:您还需要将项目添加到同一个列表中,然后按照以下评论中的建议调用notifyDataSetChanged()

+0

等待一段时间我试试你的答案 – Vikas

+0

你可以复制粘贴在浏览器中的URL来检查它的工作。没有必要在Android上运行它... – Raghunandan

+0

我已经试过你的答案,现在它显示的电影大小为20,但得到这个logcat错误和应用程序崩溃 – Vikas

0

更换

recyclerView.setAdapter(new MovieAdapter(movieList, R.layout.recyclerview_item_movie, getApplicationContext())); 

随着

movieAdapter = new MovieAdapter(movieList, R.layout.recyclerview_item_movie, this); 
recyclerView.setAdapter(movieAdapter); 

而更换

movieList= response.body().getResults(); 
movieAdapter.notifyDataSetChanged(); 

与此有关。否则notifyDataSetChanged什么也不做,因为你有一个完全不同的列表,将需要重新创建适配器

movieList.clear(); 
movieList.addAll(response.body().getResults()); 
movieAdapter.notifyDataSetChanged(); 
+0

你能解释一些更多的信息,你将如何得到一个完全不同的列表 – Vikas

+0

这是'='如何在Java中工作?您正将一个新的列表对象引用分配给您的变量。 –

+0

谢谢现在我明白了 – Vikas