0

I ran into situation where the RecyclerView with GridLayoutManager is not working on onClick(). Like ListView, when I tap/click on a picture in a GridView, the onClick is not returning the single item details. When I click on a poster of a movie, it should only display the details about the particular movie, but instead it is displaying multiple movies details in a scroll view.

Look at the code below:

public class MoviesGridAdapter extends RecyclerView.Adapter<MoviesGridAdapter.PosterViewHolder> {

    private Context context;
    private List<Movies> movieItems = new ArrayList<>();
    CustomItemClickListener listener;

    public MoviesGridAdapter(Context context, List<Movies> movieItems) {
        this.context = context;
        this.movieItems = movieItems;
    }


    @Override
    public PosterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movies_grid_view_item, parent, false);
        final MoviesGridAdapter.PosterViewHolder vh = new MoviesGridAdapter.PosterViewHolder(view);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final Context zContext = context;
                Intent intent = new Intent(zContext, MoviesDetailActivity.class);
                Movies movies = movieItems.get(vh.getAdapterPosition());
                intent.putExtra("Items Selection", movies.getPosterPath());
                intent.putExtra("Items Selection 1", movies.getTitle());
                intent.putExtra("Items Selection 2", movies.getReleaseDate());
                intent.putExtra("Items Selection 3", movies.getVoteAverage());
                intent.putExtra("Items Selection 4", movies.getOverview());
                zContext.startActivity(intent);
            }
        });
        return vh;
    }

    public void setMoviesData(List<Movies> moviesData) {
        movieItems = moviesData;
        notifyDataSetChanged();
    }


    @Override
    public void onBindViewHolder(PosterViewHolder holder, final int position) {

        Context mcontext = context;
        Movies movies = movieItems.get(position);

        String posterUrlPath = movies.getPosterPath();

        Picasso.with(mcontext)
                .load(Constants.MOVIES_POSTER_URL + posterUrlPath)
                .into(holder.poster);

    }

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

    public class PosterViewHolder extends RecyclerView.ViewHolder {
        ImageView poster;    
        public PosterViewHolder(final View itemView) {
            super(itemView);
            poster = (ImageView) itemView.findViewById(R.id.movies_image_view_retrofit);
        }
    }

}

And following is the Fragment:

public class MoviesFragment extends Fragment {

    private static final int COLUMN_COUNT = 2;
    private List<Movies> movieItems = new ArrayList<>();
    private RecyclerView recyclerView;
    private MoviesGridAdapter adapter;
    private Subscription subscription;

    public MoviesFragment() {
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.movies_fragment_content, container, false);

        GridLayoutManager layoutManager = new GridLayoutManager(getContext(), COLUMN_COUNT);
        recyclerView = (RecyclerView) view.findViewById(R.id.movies_recycler_view);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(layoutManager);

        adapter = new MoviesGridAdapter(getActivity(), movieItems);
        recyclerView.setAdapter(adapter);

        return view;
    }

    @Override
    public void onStart() {
        super.onStart();

        if (movieItems != null) {
            adapter.setMoviesData(movieItems);
        }
        loadDate();
    }

    private void loadDate() {
        MoviesAPI api = RetrofitManager.getMoviesClient().create(MoviesAPI.class);

        subscription = api.getPopularMovies(APIKeys.MOVIES_DB_API_KEY)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(
                        new Action1<MoviesResponse>() {
                            @Override
                            public void call(MoviesResponse response) {
                                movieItems = response.getMovies();
                                adapter.setMoviesData(response.getMovies());
                            }
                        }, new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {

                            }
                        }
                );
    }

}

Thank you guys for the attention. The solution I am looking is: when I click a picture from the grid view, I need the details about the particular movie like title, overview, releaseDate etc.

Ronan
  • 64
  • 1
  • 12

2 Answers2

2

Make your model parcelable or send your model fields one by one but using a different keyword. You're adding same keyword with different values in here:

intent.putExtra("Items Selection", movies.getPosterPath());
                intent.putExtra("Items Selection", movies.getTitle());
                intent.putExtra("Items Selection", movies.getReleaseDate());
                intent.putExtra("Items Selection", movies.getVoteAverage());
                intent.putExtra("Items Selection", movies.getOverview());   

Here's a tutorial link how you can make your model parcelable. And after that you can update your adapter as following:

public class MoviesGridAdapter extends RecyclerView.Adapter<MoviesGridAdapter.PosterViewHolder> {

    private Context context;
    private List<Movies> movieItems = new ArrayList<>();
    CustomItemClickListener listener;

    public MoviesGridAdapter(Context context, List<Movies> movieItems) {
        this.context = context;
        this.movieItems = movieItems;
    }


    @Override
    public PosterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movies_grid_view_item, parent, false);
        return new PosterViewHolder(view);
    }

    public void setMoviesData(List<Movies> moviesData) {
        movieItems = moviesData;
        notifyDataSetChanged();
    }


    @Override
    public void onBindViewHolder(PosterViewHolder holder, final int position) {

        Movies movie = movieItems.get(position);

        String posterUrlPath = movie.getPosterPath();

        Picasso.with(mcontext)
                .load(Constants.MOVIES_POSTER_URL + posterUrlPath)
                .into(holder.poster);

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {               
                Intent intent = new Intent(context, MoviesDetailActivity.class);          
                intent.putExtra("movie", movie) 
                context.startActivity(intent);
            }
        });

    }

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

    public class PosterViewHolder extends RecyclerView.ViewHolder {
        ImageView poster;
        public PosterViewHolder(View itemView) {
            super(itemView);
            poster = (ImageView) itemView.findViewById(R.id.movies_image_view_retrofit);
        }
    }

}
Figen Güngör
  • 12,169
  • 14
  • 66
  • 108
  • Nope. Didn't work for me. I tried your suggestion. The `onClick` works just fine itself. I need a way like `OnItemSelectedClick` in `ListIView`. – Ronan Nov 13 '16 at 23:08
  • Sorry, it should be holder.itemView.setOnClickListener inside onBindViewHolder. Your element's View is kept in itemView field of your ViewHolder, so you can add listener to your element by setting it to itemView. – Figen Güngör Nov 14 '16 at 12:47
  • `holder.mView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(context, MovieDetailsActivity.class); intent.putExtra("Title", movies.getTitle()); intent.putExtra("Overview", movies.getOverview()); context.startActivity(intent); } });` This is not working. When I click, it intents to the activity but it is listing 20s in a NestedScrollView. I only want details about just one movie. – Ronan Nov 15 '16 at 13:05
  • In that MovieDetailsActivity, you can access this detail about the selected movie. Here you send intent.putExtra("Title", movies.getTitle()) and you can access this value in onCreate of your MovieDetailsActivity like following: movieTitle = getIntent().getExtras().getString("Title"). – Figen Güngör Nov 15 '16 at 13:22
  • Wait, I have a DetailsFragment. Now I have a subscription method in the fragment. How do I handle that. I believe I can do the same on the fragment. – Ronan Nov 15 '16 at 13:28
  • After getting your values from Intent in detail activiy, create your fragment by passing those values . Check out how to pass params to fragment : http://stackoverflow.com/a/9245510/1463542 – Figen Güngör Nov 15 '16 at 13:35
1

Don't set your click listener in onCreateViewHolder. Instead set your listener in onBindViewHolder method

Amir_P
  • 8,322
  • 5
  • 43
  • 92
  • Tried that. Does not work. I implemented the `View.OnClickListener` on the Adapter class and add `holder.poster.setOnClickListener(this)` on the `onBindViewHolder`. Does not work. I get the multiple movie details on click again – Ronan Nov 13 '16 at 19:22