Karol Wiśniewski
Karol Wiśniewski

Reputation: 508

How to get item from Recycler View?

I created list using Recycler View. Now I want to get item after click. I heard about getAdapterPosition but I dont know how to use it. I try something like this but honestly dont know how to get it.

My Fragment class code:

public class FragmentOne extends Fragment {

    private static RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;
    private static RecyclerView recyclerView;
    private List<MovieDb> data;
    private MovieDb movieDb;
    static View.OnClickListener myOnClickListener;

    public static FragmentOne newInstance() {
        FragmentOne fragment = new FragmentOne();
        return fragment;
    }

    public class MovieTask extends AsyncTask<Void, Void, List<MovieDb>> {
        @Override
        protected List<MovieDb> doInBackground(Void... voids) {
            MovieResultsPage movies = new TmdbApi("f753872c7aa5c000e0f46a4ea6fc49b2").getMovies().getUpcoming("en-US", 1, "US");
            List<MovieDb> listMovies = movies.getResults();

            return listMovies;
        }

        @Override
        protected void onPostExecute(List<MovieDb> movieDb) {
            data = movieDb;
            adapter = new CustomAdapter(data);
            recyclerView.setAdapter(adapter);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

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

        myOnClickListener = new MyOnClickListener(getContext());

        recyclerView = (RecyclerView) returnView.findViewById(R.id.my_recycler_view);
        recyclerView.setHasFixedSize(true);

        layoutManager = new LinearLayoutManager(getContext());  // ???
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());

        MovieTask mt = new MovieTask();
        mt.execute();

        return returnView;
    }

    private class MyOnClickListener implements View.OnClickListener {

        private final Context context;

        private MyOnClickListener(Context context) {
            this.context = context;
        }

        @Override
        public void onClick(View v) {
            int pos1;
            pos1 = adapter.getItemId();
            movieDb = data.get(pos);
            TextView text;
            text = (TextView) v.findViewById(R.id.text1);
            Toast.makeText(getActivity(), text.getText(), LENGTH_SHORT).show();
        }

    }
}

Function OnClick is mess because I try a lot. I can get text from TextView but it is not what I want.

There is my Adapter class:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {

    private List<MovieDb> dataSet;
    public int pos;

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        TextView textViewName;
        TextView textViewVersion;
        ImageView imageViewIcon;
        int pos;

        public MyViewHolder(View itemView) {
            super(itemView);
            this.textViewName = (TextView) itemView.findViewById(R.id.text1);
            this.textViewVersion = (TextView) itemView.findViewById(R.id.text2);
            this.imageViewIcon = (ImageView) itemView.findViewById(R.id.imageView);
            itemView.setOnClickListener(FragmentOne.myOnClickListener);
        }
    }

    public CustomAdapter(List<MovieDb> data) {
        this.dataSet = data;
    }



    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent,
                                           int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cards_layout, parent, false);

        //view.setOnClickListener(FragmentOne.myOnClickListener);

        MyViewHolder myViewHolder = new MyViewHolder(view);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {

        TextView textViewName = holder.textViewName;
        TextView textViewVersion = holder.textViewVersion;
        pos = holder.getAdapterPosition();
        ImageView imageView = holder.imageViewIcon;
        Glide.with(imageView).load("https://image.tmdb.org/t/p/w500" + dataSet.get(listPosition).getPosterPath()).into(imageView);

        textViewName.setText(dataSet.get(listPosition).getOriginalTitle());
        textViewVersion.setText(dataSet.get(listPosition).getReleaseDate());
    }

    public int getPos(){
        return pos;
    }

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

I try to get position using int pos but I dont know how to use it in function OnClick.

Upvotes: 1

Views: 1542

Answers (2)

H&#229;kon Schia
H&#229;kon Schia

Reputation: 1001

Create an interface to retrieve a MovieDb when clicked:

public interface OnMovieDbClicked {
    void movieDbClicked(MovieDb movieDb);
}

In your adapter create a private member of this interface and a setter:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
    private OnMovieDbClicked onMovieDbClicked;

    public setOnMovieDbClicked(OnMovieDbClicked onMovieDbClicked) {
        this.onMovieDbClicked = onMovieDbClicked;
    }
}
    

You can then use getAdapterPosition() in the constructor of your ViewHolder and use onMovieDbClicked to send the item clicked to your fragment:

public class MyViewHolder extends RecyclerView.ViewHolder {
    public MyViewHolder(View itemView) {
        // Initialize your views

        itemView.setOnClickListener(view -> {
            int pos = getAdapterPosition();
            
            if (onMovieDbClicked != null && pos != RecyclerView.NO_POSITION) {
                MovieDb movieDb = dataSet.get(pos);
                onMovieDbClicked.movieDbClicked(movieDb);
            }
        });
    }
}

When you're creating your adapter in your fragment, call setOnMovieDbClicked() as well:

adapter = new CustomAdapter(data);
adapter.setOnMovieDbClicked(movieDb -> {
    // Do whatever you want with movieDb
});

Upvotes: 1

BlackHatSamurai
BlackHatSamurai

Reputation: 23483

I would do something along these lines:

  1. Adjust your MyOnClickListener to something like this:

     private class MyOnClickListener implements View.OnClickListener {
    
     private final Context context;
     private int position;
    
     //Adjust your constructor to take in the context as a paramater
     private MyOnClickListener(Context context, int position) {
         this.context = context;
         this.position = position;
     }
    
     @Override
     public void onClick(View v) {
         //not sure what you're doing with movieDB here....
         movieDb = data.get(position);
         TextView text;
         text = (TextView) v.findViewById(R.id.text1);
         Toast.makeText(getActivity(), text.getText(), LENGTH_SHORT).show();
     }
    

    } }

  2. Update your CustomAdapter class:

     public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
    
     private List<MovieDb> dataSet;
     public int pos;
     private Context context;
    
     public CustomAdapter(List<MovieDb> data, Context context) {
           this.dataSet = data;
           this.context = context;
     }
    
     //You'll need this later to update the data set
     public void updateDataSet(List<MovieDB data){
          this.dataSet = data; 
          notifyDataSetChange();
    

    ...

  3. In your onBindViewHolder do something like:

     @Override
    public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {
    
     TextView textViewName = holder.textViewName;
     TextView textViewVersion = holder.textViewVersion;
     pos = holder.getAdapterPosition();
     ImageView imageView = holder.imageViewIcon;
     Glide.with(imageView).load("https://image.tmdb.org/t/p/w500" + dataSet.get(listPosition).getPosterPath()).into(imageView);
    
     textViewName.setText(dataSet.get(listPosition).getOriginalTitle());
     textViewVersion.setText(dataSet.get(listPosition).getReleaseDate());
    
     holder.setOnClickListener(new MyOnclickListener(context, listPosition));
    

    }

  4. Move your adapter call from the MovieTask to the FragmentOne onCreateMethod:

       @Override
       public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         View returnView = inflater.inflate(R.layout.fragment_one, container, false);
    
         myOnClickListener = new MyOnClickListener(getContext());
    
         recyclerView = (RecyclerView) returnView.findViewById(R.id.my_recycler_view);
         recyclerView.setHasFixedSize(true);
    
         layoutManager = new LinearLayoutManager(getContext());  // ???
         recyclerView.setLayoutManager(layoutManager);
         recyclerView.setItemAnimator(new DefaultItemAnimator());
        adapter = new CustomAdapter(getContext(), data);
    
         MovieTask mt = new MovieTask();
         mt.execute();
    
         return returnView;
     }
    
  5. In your Movie Task update you data set:

         @Override
         protected void onPostExecute(List<MovieDb> movieDb) {
             data = movieDb;
             adapter.updateDataSet(data);
         }
    

You might need to make some minor adjustments to this code, but it should give you a basic idea of how to accomplish what you are trying to do.

Best of luck :)

Upvotes: 1

Related Questions