A similar question has already been answered here, but none of the solutions helped in my case.
I'm trying to get movie reviews data using Retrofit and then using it to populate my RecyclerView.
First I get a response which is then saved in my MovieReviewsList
Code for MovieReviewsList:
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class MovieReviewsList {
@SerializedName("results")
private final List<MovieReview> movieReviewsList;
public MovieReviewsList(List<MovieReview> movieReviewsList) {
this.movieReviewsList = movieReviewsList;
}
public List<MovieReview> getMovieReviewsList() {
return movieReviewsList;
}
public int size() {
return movieReviewsList.size();
}
}
This class just stores a List of MovieReviews.
Code for MovieReviews:
import com.google.gson.annotations.SerializedName;
public class MovieReview {
@SerializedName("author")
private final String movieReviewAuthor;
@SerializedName("url")
private final String movieReviewUrl;
public MovieReview(String movieReviewAuthor, String movieReviewUrl) {
this.movieReviewAuthor = movieReviewAuthor;
this.movieReviewUrl = movieReviewUrl;
}
public String getMovieReviewAuthor() {
return movieReviewAuthor;
}
public String getMovieReviewUrl() {
return movieReviewUrl;
}
Then I'm trying to display that data in my activity. But every time I run my app I get No adapter attached; skipping layout error.
Here is my activity:
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.MenuItem;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.example.android.popularmovies.R;
import com.example.android.popularmovies.databinding.ActivityDetailBinding;
import com.example.android.popularmovies.network.movies.Movie;
import com.example.android.popularmovies.network.movies.MovieReview;
import com.example.android.popularmovies.network.movies.MovieReviewsList;
import com.example.android.popularmovies.network.movies.MovieTrailersList;
import com.example.android.popularmovies.network.MoviesClient;
import com.example.android.popularmovies.network.NetworkUtils;
import com.example.android.popularmovies.network.RetrofitInstance;
import com.google.gson.Gson;
import com.squareup.picasso.Picasso;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class DetailActivity extends AppCompatActivity {
private static final String TAG = "DetailActivity";
private MovieTrailersAdapter movieTrailersAdapter;
private MovieReviewsAdapter movieReviewsAdapter;
private Disposable movieTrailersCall;
private Disposable movieReviewsCall;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Intent launchingIntent = getIntent();
if (launchingIntent == null || !launchingIntent.hasExtra(MainActivity.INTENT_EXTRA_MOVIE)) {
finish();
}
String movieAsJson = launchingIntent.getStringExtra(MainActivity.INTENT_EXTRA_MOVIE);
Movie movie = new Gson().fromJson(movieAsJson, Movie.class);
// Trailers
RecyclerView movieTrailersRecyclerView = findViewById(R.id.trailers_rv);
LinearLayoutManager trailersLinearLayoutManager = new LinearLayoutManager(this);
movieTrailersRecyclerView.setLayoutManager(trailersLinearLayoutManager);
movieTrailersAdapter = new MovieTrailersAdapter();
movieTrailersRecyclerView.setAdapter(movieTrailersAdapter);
// Reviews
RecyclerView movieReviewsRecyclerView = findViewById(R.id.reviews_rv);
LinearLayoutManager reviewsLinearLayoutManager = new LinearLayoutManager(this);
movieReviewsRecyclerView.setLayoutManager(reviewsLinearLayoutManager);
movieReviewsAdapter = new MovieReviewsAdapter();
movieReviewsRecyclerView.setAdapter(movieReviewsAdapter);
// Network call
getMovieTrailersAndReviews(movie);
ActivityDetailBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_detail);
Picasso.with(this)
.load(NetworkUtils.getImageUrl(movie.getThumbnailPath()))
.into(binding.thumbnailIv);
binding.setMovie(movie);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void getMovieTrailersAndReviews(Movie movie) {
if (movie == null || !NetworkUtils.isConnectedToInternet(this)) {
Toast.makeText(this, "Please connect to internet", Toast.LENGTH_SHORT).show();
return;
}
Retrofit retrofit = RetrofitInstance.getRetrofitInstance();
MoviesClient moviesClient = retrofit.create(MoviesClient.class);
Call<MovieTrailersList> movieTrailersCall = moviesClient.getMovieTrailers(movie.getId(), NetworkUtils.API_KEY);
movieTrailersCall.enqueue(new Callback<MovieTrailersList>() {
@Override
public void onResponse(Call<MovieTrailersList> call, Response<MovieTrailersList> response) {
movieTrailersAdapter.setData(response.body());
}
@Override
public void onFailure(Call<MovieTrailersList> call, Throwable t) {
}
});
Call<MovieReviewsList> movieReviewsCall = moviesClient.getMovieReviews(movie.getId(), NetworkUtils.API_KEY);
movieReviewsCall.enqueue(new Callback<MovieReviewsList>() {
@Override
public void onResponse(Call<MovieReviewsList> call, Response<MovieReviewsList> response) {
movieReviewsAdapter.setData(response.body());
}
@Override
public void onFailure(Call<MovieReviewsList> call, Throwable t) {
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
I have logged a bunch of times and I have made sure that my network call always returns data. Then I set that data, inside of my onResponse callbacks, in my adapter.
Here is the code for my adapter:
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.android.popularmovies.R;
import com.example.android.popularmovies.network.movies.MovieReview;
import com.example.android.popularmovies.network.movies.MovieReviewsList;
public class MovieReviewsAdapter extends RecyclerView.Adapter<MovieReviewsAdapter.ViewHolder> {
private static final String TAG = "MovieReviewsAdapter";
private MovieReviewsList reviewsList;
public MovieReviewsAdapter() { }
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View containerView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.review_item, parent, false);
return new ViewHolder(containerView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
MovieReview movieReview = reviewsList.getMovieReviewsList().get(position);
holder.reviewedByTextView.setText(movieReview.getMovieReviewAuthor());
}
@Override
public int getItemCount() {
if (reviewsList == null) {
return 0;
}
return reviewsList.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
final TextView reviewedByTextView;
ViewHolder(View itemView) {
super(itemView);
reviewedByTextView = itemView.findViewById(R.id.review_by_tv);
}
}
public void setData(MovieReviewsList movieReviewsList) {
this.reviewsList = movieReviewsList;
notifyDataSetChanged();
}
}
Log errors:
02-21 10:21:31.708 17295-17295/com.example.android.popularmovies E/RecyclerView: No adapter attached; skipping layout
I have read this post which is on the same topic, but I haven't found a solution.
Any help would be appreciated. Thanks!