我正在创建将使用TMDb API的电影列表应用程序。我创建了两个spearate片段,分别调用了api方法。
有一个java.lang.NullPointerException:尝试在出现空对象引用错误时调用接口方法'int java.util.List.size()'。 这是我的错误代码:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: sg.edu.tp.moviex, PID: 6404
java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
at sg.edu.tp.moviex.Adapter.MoviesAdapter.getItemCount(MoviesAdapter.java:56)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3722)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3527)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1737)
at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4928)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:655)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main
这是片段Java代码:
public class LatestBlockbustersFragment extends Fragment {
View view;
private RecyclerView recyclerView1;
private MoviesAdapter moviesAdapter;
private List<Movie> movieList;
private SwipeRefreshLayout swipeContainer1;
public static final String LOG_TAG = MoviesAdapter.class.getName();
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
view = inflater.inflate(R.layout.fragment_home, container, false);
initViews();
return view;
}
@Override
public void onCreate(@Nullable Bundle SavedInstanceState){
super.onCreate(SavedInstanceState);
movieList = new ArrayList<>();
}
private void loadJSON(){
try {
if (BuildConfig.THE_MOVIE_DB_API_TOKEN.isEmpty()) {
Toast.makeText(getActivity(), "Please obtain API key from themoviedb.org", Toast.LENGTH_SHORT).show();
return;
}
Client Client = new Client();
Service apiService = Client.getClient().create(Service.class);
// API service: getLatestMovies ; change to other forms to get other types
Call<MovieResponse> call = apiService.getLatestMovies(BuildConfig.THE_MOVIE_DB_API_TOKEN);
call.enqueue(new Callback<MovieResponse>() {
@Override
public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) {
List<Movie> movies = response.body().getResults();
recyclerView1.setAdapter(new MoviesAdapter(getActivity(), movies));
recyclerView1.smoothScrollToPosition(0);
if (swipeContainer1.isRefreshing()){
swipeContainer1.setRefreshing(false);
}
}
@Override
public void onFailure(Call<MovieResponse> call, Throwable t) {
Log.d("Error", t.getMessage());
Toast.makeText(getActivity(), "Error Fetching Data!", Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
Log.d("Error", e.getMessage());
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
private void initViews(){
recyclerView1 = view.findViewById(R.id.recycler_view);
movieList = new ArrayList<>();
moviesAdapter = new MoviesAdapter(getActivity(), movieList);
recyclerView1.setLayoutManager(new GridLayoutManager(getActivity(),2));
recyclerView1.setItemAnimator(new DefaultItemAnimator());
recyclerView1.setAdapter(moviesAdapter);
moviesAdapter.notifyDataSetChanged();
loadJSON();
//TODO Look at SwipeRefreshLayout and Lambda Expressions
swipeContainer1 = view.findViewById(R.id.swipeContainer);
swipeContainer1.setColorSchemeResources(android.R.color.holo_orange_dark);
swipeContainer1.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
initViews();
}
});
}
这是MovieAdapter代码,其中错误是:
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.telecom.Call;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import java.util.List;
import sg.edu.tp.moviex.Activities.MovieDetailActivity;
import sg.edu.tp.moviex.Model.Movie;
import sg.edu.tp.moviex.R;
public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MyViewHolder> {
private Context mContext;
private List<Movie> movieList;
public MoviesAdapter(Context mContext, List<Movie> movieList){
this.mContext = mContext;
this.movieList = movieList;
}
// int i refers to the count/position
@Override
public MoviesAdapter.MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i){
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.movie_card, viewGroup, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(final MoviesAdapter.MyViewHolder viewHolder, int i){
// Calls getOriginalTitle from movie.java and sets as movie title
viewHolder.title.setText(movieList.get(i).getOriginalTitle());
// Calls getVoteAverage from movie.java and sets to userrating
String vote = Double.toString(movieList.get(i).getVoteAverage());
viewHolder.userrating.setText(vote);
// Calls getPosterPath from movie.java and sets poster as thumbnail
Glide.with(mContext).load(movieList.get(i).getPosterPath())
.placeholder(R.drawable.load).into(viewHolder.thumbnail);
}
@Override
public int getItemCount(){
return movieList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder{
public TextView title, userrating;
public ImageView thumbnail;
public MyViewHolder(View view){
super(view);
title = view.findViewById(R.id.title);
userrating = view.findViewById(R.id.userrating);
thumbnail = view.findViewById(R.id.thumbnail);
view.setOnClickListener(v -> {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
Movie clickedDataItem = movieList.get(position);
Intent intent = new Intent(mContext, MovieDetailActivity.class);
intent.putExtra("original_title", movieList.get(position).getOriginalTitle());
intent.putExtra("poster_path", movieList.get(position).getPosterPath());
intent.putExtra("overview", movieList.get(position).getOverview());
intent.putExtra("vote_average",Double.toString(movieList.get(position).getVoteAverage()));
intent.putExtra("release_date", movieList.get(position).getReleaseDate());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
Toast.makeText(v.getContext(), "You clicked" + clickedDataItem.getOriginalTitle(), Toast.LENGTH_SHORT).show();
}
});
}
}
请帮助。预先感谢。
答案 0 :(得分:0)
在片段中,您必须将电影添加到movieList
movieList.add(movies);
我建议您在API响应中执行以下操作:
try {
JSONObject job = new JSONObject(response);
if (movieList != null) {
movieList.clear();
}
JSONArray jarray = job.getJSONArray("whatever array name");
if (jarray.length() > 0) {
for (int i = 0; i < jarray.length(); i++) {
JSONObject json_obj = jarray.getJSONObject(i);
Movies type = new Movies();
type.setOriginalTitle(json_obj.getString("parameter name"));
type.setVoteAverage(json_obj.getString("parameter name"));
type.setPosterPath(json_obj.getString("parameter name"));
movieList.add(type);
}
if (movieList != null) {
Log.d("asher","movie list "+movieList);
MoviesAdapter adapter = new MoviesAdapter(activity, movieList);
recyclerView1.setAdapter(adapter);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
现在在适配器类中,您可以通过onBindViewHolder()中的位置获取它。 将Log放入您的onBindViewHolder方法中,然后检查是否所有数据都在传输。 并在fragment类中执行相同的操作,在将movieList设置为适配器之前,将其放入日志。