My list always Null. What am I doing wrong? - java

I am doing some kind of Medication Reminder App for our school and I am trying to create an Expandable RecyclerView based on a video I watch and practically followed step by step. Did everything practically the same but we created a Database instead of just fixed values. The problem I have is that after initializing in the Main Activity, my list value is always Null and that my adapter is returning a NULL. What am I doing wrong?
Here is my code.
MediReminders.java
I've decided to remove this because its just a bunch of getters and setters
MedAdapters.java
public class MedAdapters extends RecyclerView.Adapter<MedAdapters.MediRemindersVH> {
List<MediReminders> MedList;
public MedAdapters(List<MediReminders> MedList) {
this.MedList = MedList;
}
#NonNull
#Override
public MedAdapters.MediRemindersVH onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row,parent,false);
return new MediRemindersVH(view);
}
#Override
public void onBindViewHolder(#NonNull MedAdapters.MediRemindersVH holder, int position) {
MediReminders mediReminders = MedList.get(position);
holder.med_nameTxt.setText(mediReminders.getMed_name());
holder.med_typeTxt.setText(mediReminders.getMed_type());
holder.fromdatedetailTxt.setText(mediReminders.getFromDatedetail());
holder.todatedetailTxt.setText(mediReminders.getToDatedetail());
holder.timedetailTxt.setText(mediReminders.getTimedetail());
holder.whendetailTxt.setText(mediReminders.getWhendetail());
holder.notesdetailTxt.setText(mediReminders.getNotesdetail());
boolean isExpandable = MedList.get(position).isExpandable();
holder.expandableLayout.setVisibility(isExpandable ? View.VISIBLE : View.GONE);
}
#Override
public int getItemCount() {
return MedList.size();
}
public class MediRemindersVH extends RecyclerView.ViewHolder {
TextView med_nameTxt, med_typeTxt, fromdatedetailTxt, todatedetailTxt, timedetailTxt, whendetailTxt, notesdetailTxt;
LinearLayout linearLayout;
RelativeLayout expandableLayout;
public MediRemindersVH(#NonNull View itemView) {
super(itemView);
med_nameTxt = itemView.findViewById(R.id.medname);
med_typeTxt = itemView.findViewById(R.id.auto_complete_txt);
fromdatedetailTxt = itemView.findViewById(R.id.fromdate);
todatedetailTxt = itemView.findViewById(R.id.todate);
timedetailTxt = itemView.findViewById(R.id.datetime);
whendetailTxt = itemView.findViewById(R.id.radioGroup);
notesdetailTxt = itemView.findViewById(R.id.notes);
linearLayout = itemView.findViewById(R.id.linear_layout);
expandableLayout = itemView.findViewById(R.id.expandable_layout);
linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MediReminders mediReminders = MedList.get(getAdapterPosition());
mediReminders.setExpandable(!mediReminders.isExpandable());
notifyItemChanged(getAdapterPosition());
}
});
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
List<MediReminders> MedList;
MedAdapters adapter = new MedAdapters(MedList);
ImageButton addNewButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recyclerView = findViewById(R.id.MedList);
setContentView(R.layout.activity_main_list);
initData();
setRecyclerView();
}
private void setRecyclerView () {
//problem is specifically this one...
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
}
private void initData () {
MedList = new ArrayList<>();
MedList.add(new MediReminders("Paracetamol", "Tablet", "Apr 26, 2022", "May 9,2022", "6:30 PM", "Before Meal", "Take in water first"));
}
}

First, Try to check your application with Fixed hard coded values.
If it's working fine.
Second, run and check your database query on some dbms tool.

Related

How can I show/hide a layout in the main activity from a RecyclerView in android studio java?

I have an activity which consists of a recycler view for generating buttons (from a different layout file) and a layout with elements for confirmation.
I want to make it so when I click on the button "NEW GAME" (in the Recyclerview class), the confirmationLayout (in the MainMenu Activity) shows. But I can't, can someone help me?
MainMenu Class
public class MainMenu extends AppCompatActivity {
private ImageView profileIcon;
private TextView username;
private RelativeLayout newGameConfirmationLayout;
private TextView yesButton, noButton;
private RecyclerView buttonRecyclerView;
private ButtonRecyclerAdapter adapter;
private DataHandler dataHandler;
private ArrayList<String> buttonNames = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
newGameConfirmationLayout = findViewById(R.id.newGameConfirmationLayout);
yesButton = findViewById(R.id.yesButton);
noButton = findViewById(R.id.noButton);
buttonRecyclerView = findViewById(R.id.buttonRecyclerView);
buttonRecyclerView.setLayoutManager(new LinearLayoutManager(MainMenu.this));
if(General.infoSaved){buttonNames.add("CONTINUE GAME");}
buttonNames.add("NEW GAME");
buttonNames.add("CHANGE USER");
buttonNames.add("PRACTICE");
buttonNames.add("EXERCISE LIST");
adapter = new ButtonRecyclerAdapter(buttonNames, MainMenu.this);
buttonRecyclerView.setAdapter(adapter);
yesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startGame();
}
});
noButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newGameConfirmationLayout.setVisibility(View.INVISIBLE);
}
});
}
private void startGame(){}
public void show_confirmationLayout(){
newGameConfirmationLayout.setVisibility(View.VISIBLE);
}
RecyclerView Class
public class ButtonRecyclerAdapter extends RecyclerView.Adapter<ButtonRecyclerAdapter.buttonHolder>{
private ArrayList<String> buttonNames;
private Context context;
public ButtonRecyclerAdapter(ArrayList<String> loginButtonNames, Context context) {
this.buttonNames = loginButtonNames;
this.context = context;
}
#NonNull
#Override
public buttonHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.button_block,parent,false);
return new buttonHolder(view);
}
#Override
public void onBindViewHolder(#NonNull buttonHolder holder, int position) {
holder.button.setText(buttonNames.get(position));
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String buttonName = holder.button.getText().toString();
switch (buttonName){
case "NEW GAME":
MainMenu mainMenu = new MainMenu();
mainMenu.show_confirmationLayout();
break;
}
}
});
}
#Override
public int getItemCount() {
return buttonNames.size();
}
public class buttonHolder extends RecyclerView.ViewHolder{
private Button button;
public buttonHolder(#NonNull View itemView) {
super(itemView);
button = itemView.findViewById(R.id.buttonblock);
}
}
}
I tried adding it as a class (as above) but I get the error that the layout is a null object / However when I try to write the ame line of code directly in the activity it works.
There's a method I personally use in my RecyclerView's Adapter and ViewHolder is to set the width and height of your item's ViewGroup to 0.
Here's the method you can add to your adapter class which takes item position that you want to hide:
public void hideFeedItem(int position){
RecyclerView.ViewHolder holder = getViewHolderAtPosition(position);
if(holder != null){
ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
params.height=0;
params.width= 0;
holder.itemView.setLayoutParams(params);
}
}
Where itemview is the root ViewGroup that should be already defined in your ViewHolder in your case should be buttonHolder.

View color changing on click changes at every 8th position RecyclerView

So when i click on the 0 position of recyclerview to change the color of the view it also changes the color at 8th, 16th and 24th position (i have a total of 26 items in recyclerview), if i click on position 1 it changes color at 1st, 9th, 17th and 25th and so on. how do i fix this
My recyclerview adapter is
public class AdapterOccupiedRoomCleaning extends RecyclerView.Adapter<AdapterOccupiedRoomCleaning.ViewHolder> {
private List<ItemsAdapter> mList;
private Context mContext;
public AdapterOccupiedRoomCleaning(List<ItemsAdapter> list, Context context){
super();
mList = list;
mContext = context;
}
#NonNull
#Override
public AdapterOccupiedRoomCleaning.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.occupiedrooms_cleaning_item, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
((ViewHolder) viewHolder).setUrduText.setText(itemAdapter.getUrdutext());
((ViewHolder) viewHolder).setEnglishText.setText(itemAdapter.getEnglishText());
((ViewHolder) viewHolder).setCleaningImage.setImageResource(itemAdapter.getImage());
// ((ViewHolder) viewHolder).background.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
//
// //viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
//
// Toast.makeText(mContext, "Recycle Click " + viewHolder.setEnglishText.getText().toString(), Toast.LENGTH_SHORT).show();
// }
// });
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
#Override
public int getItemCount() {
//notifyDataSetChanged();
return mList.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public TextView setUrduText, setEnglishText;
public ImageView setCleaningImage;
public View background;
public ViewHolder(View itemView) {
super(itemView);
setUrduText = (TextView) itemView.findViewById(R.id.urduTextView);
setEnglishText = (TextView) itemView.findViewById(R.id.englishTextView);
setCleaningImage = (ImageView) itemView.findViewById(R.id.imageCleaning);
background = (View) itemView.findViewById(R.id.backgroundColor);
}
}
}
My java class is
public class OccupiedRoomCleaning extends AppCompatActivity {
String getQrCode, patientMRNO, roomNumber;
private RecyclerView mRecycleview;
private List<ItemsAdapter> mList = new ArrayList<>();
private AdapterOccupiedRoomCleaning mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_occupied_room_cleaning);
getQrCode = getIntent().getExtras().getString("qrcode");
init();
addList();
adapter();
}
private void init(){
mRecycleview = findViewById(R.id.recyclerview);
}
private void addList(){
ItemsAdapter itemAdapter = new ItemsAdapter();
itemAdapter.setImage(R.drawable.pillowclean);
itemAdapter.setUrdutext("sdf");
itemAdapter.setEnglishText("Pillow Parachute Cover Cleaning");
mList.add(itemAdapter);
itemAdapter = new ItemsAdapter();
itemAdapter.setImage(R.drawable.bedclean);
itemAdapter.setUrdutext("sdfs");
itemAdapter.setEnglishText("Patient Bed Cleaning(Blood Spots)");
mList.add(itemAdapter);
//... more items
}
private void adapter(){
Log.d("anhtt","mlist : " +mList.size());
mAdapter = new AdapterOccupiedRoomCleaning(mList, this);
mRecycleview.setAdapter(mAdapter);
mRecycleview.setLayoutManager(new LinearLayoutManager(this));
}
}
what am i doing wrong here that it changes color at every 8th item
This seems likely to be a problem with the view recycling behavior of RecyclerView.
Generally, you're going to run into problems like this one any time you have some property of your ViewHolder that you only conditionally set inside onBindViewHolder(). That is, because you do not always update the background color of your ViewHolder, you'll get the "wrong" color when it is recycled and reused.
You will have to somehow store the "clicked" or "selected" state in your list of items, and then update the background color of your ViewHolder every time in onBindViewHolder(). Something like this:
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
...
if (itemAdapter.isSelected()) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
} else {
viewHolder.background.setBackgroundColor(Color.parseColor("#FFFFFF"));
}
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemAdapter.setSelected(true);
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
Note that it would be better to define the click listener inside onCreateViewHolder() and to use notifyItemChanged() instead of manually updating the background color, but that's outside the scope of this question.
Since, a Recycler view reuses the views and do not create new views, you need to set default color in onBindViewHolder function.
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
((ViewHolder) viewHolder).setUrduText.setText(itemAdapter.getUrdutext());
((ViewHolder) viewHolder).setEnglishText.setText(itemAdapter.getEnglishText());
((ViewHolder) viewHolder).setCleaningImage.setImageResource(itemAdapter.getImage());
// Add this line
((ViewHolder) viewHolder).background.setBackgroundColor(Color.parseColor("default color"));
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}

Recyclerview doesn't show any data after swiping one of the rows

I've added swipe to my app, to delete specified note. For couple of days, I've facing problem with displaying data after swipe. For clarify:
Let's say, we have two items in recycler view. Whenever we swipe one of them, the second one should be visible, but it's not until I'll re-run the app. How I may solve it?
Main Activity
public class MainActivity extends AppCompatActivity implements MemoAdapter.OnNoteListener {
private static final String TAG = "MainActivity";
//Vars
private ArrayList<Note> mNotes = new ArrayList<>();
private MemoRepository mRepository;
private MemoAdapter mMemoAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRepository = new MemoRepository(this);
Toolbar toolbar = (Toolbar) findViewById(R.id.memoToolbar);
setSupportActionBar(toolbar);
setTitle("My memos");
initRecyclerView();
}
//This method would be called after getting result from memo_content such as new memo, or edited existing memo.
#Override
protected void onResume() {
super.onResume();
getMemos();
}
private void getMemos(){
mRepository.getAllMemos().observe(this, new Observer<List<Note>>() {
#Override
public void onChanged(List<Note> notes) {
if (mNotes.size() > 0){
notes.clear();
}
if (notes != null){
mNotes.addAll(notes);
mMemoAdapter.watchMemoChanges((ArrayList<Note>) notes);
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.icon_menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.addNewNote:
Toast.makeText(this, "Click!", Toast.LENGTH_SHORT).show();
startActivity(new Intent(this, memo_content.class));
break;
case R.id.deleteAllNotes:
Toast.makeText(this, "Delete!", Toast.LENGTH_SHORT).show();
mRepository.deleteAllMemos();
break;
}
return super.onOptionsItemSelected(item);
}
private void initRecyclerView(){
//UI
RecyclerView mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
mMemoAdapter = new MemoAdapter(mNotes, this);
new ItemTouchHelper(itemTouch).attachToRecyclerView(mRecyclerView);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mMemoAdapter);
}
#Override
public void onMemoClick(int position) {
Intent intent = new Intent(this, memo_content.class);
intent.putExtra("memo_content", mNotes.get(position));
startActivity(intent);
}
private ItemTouchHelper.SimpleCallback itemTouch = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.START | ItemTouchHelper.LEFT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
mRepository.deleteMemo(mNotes.get(viewHolder.getAdapterPosition()));
Log.d(TAG, "onSwiped: "+mNotes.get(viewHolder.getAdapterPosition()));
}
};
}
Adapter
public class MemoAdapter extends RecyclerView.Adapter<MemoAdapter.MemoViewHolder> {
private ArrayList<Note> mNotes;
private OnNoteListener mListener;
public class MemoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView title, timestamp;
private MemoViewHolder(#NonNull final View itemView) {
super(itemView);
this.title = (TextView) itemView.findViewById(R.id.title);
this.timestamp = (TextView) itemView.findViewById(R.id.timestamp);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mListener.onMemoClick(getAdapterPosition());
}
}
public MemoAdapter(ArrayList<Note> notes, OnNoteListener listener) {
this.mNotes = notes;
this.mListener = listener;
}
#NonNull
#Override
public MemoViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_memo, parent, false);
return new MemoViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MemoViewHolder holder, int position) {
holder.title.setText(mNotes.get(position).getTitle());
holder.timestamp.setText(mNotes.get(position).getTimestamp());
}
public void watchMemoChanges(ArrayList<Note> notes){
this.mNotes = notes;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return mNotes.size();
}
public interface OnNoteListener{
void onMemoClick(int position);
}
Short answer:
You need to remove the statement notes.clear() when you receive a change in the LiveData list from the database via the observer.
Detailed answer
When you first run your app, it will show all right list because the condition if (mNotes.size() > 0) is not met, and so the received list won't be cleared via notes.clear(), so the RecyclerView will display the right data.
But when you delete a note, then when the observer is triggered again with the new list, the condition if (mNotes.size() > 0) will be met, so you will clear the list that is coming from the database before feeding the adapter with it, so the RecyclerView will be free of data.
So to solve this please replace notes.clear(); with mNotes.clear();
So the right code will be:
private void getMemos(){
mRepository.getAllMemos().observe(this, new Observer<List<Note>>() {
#Override
public void onChanged(List<Note> notes) {
if (mNotes.size() > 0){
mNotes.clear();
}
if (notes != null){
mNotes.addAll(notes);
mMemoAdapter.watchMemoChanges((ArrayList<Note>) notes);
}
}
});
}
Wish that help you out.
I didn't examine the rest of code, please let me know if there is another issue to help more

Problems calling notifyDataSetChange in RecyclerViewHolder

I am having problems updating my RecyclerView with new data. If I press a confirmation button on a CardView in the first tab, the card should get added to the second tab but it won't update it there until I rotate the screen. I get the data for the card from reading a text file. Please advise me how to call the notifyDataSetChange method after I have added the new data to my text file. I have tried everything and all I get is NullPointerExceptions. The RecyclerViews are in fragments and I use FragementStatePagerAdapter.
I'll put some of my classes here. Ask if you need more information.
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag) {
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag);
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag) {
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
SectionsPagerAdapter.java
public class SectionsPagerAdapter extends FragmentStatePagerAdapter{
private ViewPager viewPager;
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public void addFragment(Fragment fragment, String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
CompletedFragment.java
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed");
recyclerView.setAdapter(adapter);
return view;
}
}
}
EDIT:
Added the code for the second fragment, which is the one that should be updated after the onClick at RecyclerViewHolder-class.
You have to add a function in your adapter for adding data:
public void addData(String title, String desc, String point, String date) {
this.mListTitle.add(title);
this.mListDesc.add(desc);
this.mListPoints.add(point);
this.mListDates.add(date);
notifyDataSetChanged();
}
If you want to enable animations call notifyItemInserted() instead of notifyDataSetChanged();
It is important that you add a String to every list because in your onBindViewHolder() you get the item to display from every list with list.get(position). Otherwise you'll get a IndexOutOfBoundsException.
You can create an interface and use as a callback. Send it as a parameter of the RecyclerViewAdapter and then to your RecyclerViewHolder. When the item should be added you call the callback that will get you back to your fragment. There you can read the file again and call notifyDataSetChanged.
I know i explain pretty bad so i will try to change your code so that it does what i said:
this will be your RecyclerViewAdapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
private Runnable callback;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag, Runnable callBack) {
//add the callback here(Runnable) and save it into a local variable
this.callback=callback;
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag, callback);
//send the callback to your viewHolder
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag, Runnable callback) {
//ADD the callback to the parameters list here
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
//call the callback
callback.run();
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
And this will be your fragment:
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed", new Runnable() {
#Override
public void run() {
//here read the list again and call notifyDataSetChanged on your recycler
}
});
);
recyclerView.setAdapter(adapter);
return view;
}
}
}
Hope it helps and it works for you. If i did anything wrong, let me know, i can't run the code right now so...
edited, i forgot to add code in the callback

Why doesn't RecyclerView have onItemClickListener()?

I was exploring RecyclerView and I was surprised to see that RecyclerView does not have onItemClickListener().
I've two question.
Main Question
I want to know why Google removed onItemClickListener()?
Is there a performance issue or something else?
Secondary Question
I solved my problem by writing onClick in my RecyclerView.Adapter:
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
#Override
public void onClick(View v) {
}
}
Is this ok / is there any better way?
tl;dr 2016 Use RxJava and a PublishSubject to expose an Observable for the clicks.
public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data", "In", "Adapter" };
private final PublishSubject<String> onClickSubject = PublishSubject.create();
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final String element = mDataset[position];
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onClickSubject.onNext(element);
}
});
}
public Observable<String> getPositionClicks(){
return onClickSubject.asObservable();
}
}
Original Post:
Since the introduction of ListView, onItemClickListener has been problematic. The moment you have a click listener for any of the internal elements the callback would not be triggered but it wasn't notified or well documented (if at all) so there was a lot of confusion and SO questions about it.
Given that RecyclerView takes it a step further and doesn't have a concept of a row/column, but rather an arbitrarily laid out amount of children, they have delegated the onClick to each one of them, or to programmer implementation.
Think of Recyclerview not as a ListView 1:1 replacement but rather as a more flexible component for complex use cases. And as you say, your solution is what google expected of you. Now you have an adapter who can delegate onClick to an interface passed on the constructor, which is the correct pattern for both ListView and Recyclerview.
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public IMyViewHolderClicks mListener;
public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) {
super(itemLayoutView);
mListener = listener;
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
imgViewIcon.setOnClickListener(this);
itemLayoutView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v instanceof ImageView){
mListener.onTomato((ImageView)v);
} else {
mListener.onPotato(v);
}
}
public static interface IMyViewHolderClicks {
public void onPotato(View caller);
public void onTomato(ImageView callerImage);
}
}
and then on your adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data" };
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout, parent, false);
MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() {
public void onPotato(View caller) { Log.d("VEGETABLES", "Poh-tah-tos"); };
public void onTomato(ImageView callerImage) { Log.d("VEGETABLES", "To-m8-tohs"); }
});
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Get element from your dataset at this position
// Replace the contents of the view with that element
// Clear the ones that won't be used
holder.txtViewTitle.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.length;
}
...
Now look into that last piece of code: onCreateViewHolder(ViewGroup parent, int viewType) the signature already suggest different view types. For each one of them you'll require a different viewholder too, and subsequently each one of them can have a different set of clicks. Or you can just create a generic viewholder that takes any view and one onClickListener and applies accordingly. Or delegate up one level to the orchestrator so several fragments/activities have the same list with different click behaviour. Again, all flexibility is on your side.
It is a really needed component and fairly close to what our internal implementations and improvements to ListView were until now. It's good that Google finally acknowledges it.
Why the RecyclerView has no onItemClickListener
The RecyclerView is a toolbox, in contrast of the old ListView it has less build in features and more flexibility. The onItemClickListener is not the only feature being removed from ListView. But it has lot of listeners and method to extend it to your liking, it's far more powerful in the right hands ;).
In my opinion the most complex feature removed in RecyclerView is the Fast Scroll. Most of the other features can be easily re-implemented.
If you want to know what other cool features RecyclerView added read this answer to another question.
Memory efficient - drop-in solution for onItemClickListener
This solution has been proposed by Hugo Visser, an Android GDE, right after RecyclerView was released. He made a licence-free class available for you to just drop in your code and use it.
It showcase some of the versatility introduced with RecyclerView by making use of RecyclerView.OnChildAttachStateChangeListener.
Edit 2019: kotlin version by me, java one, from Hugo Visser, kept below
Kotlin / Java
Create a file values/ids.xml and put this in it:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="item_click_support" type="id" />
</resources>
then add the code below to your source
Kotlin
Usage:
recyclerView.onItemClick { recyclerView, position, v ->
// do it
}
(it also support long item click and see below for another feature I've added).
implementation (my adaptation to Hugo Visser Java code):
typealias OnRecyclerViewItemClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Unit
typealias OnRecyclerViewItemLongClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Boolean
class ItemClickSupport private constructor(private val recyclerView: RecyclerView) {
private var onItemClickListener: OnRecyclerViewItemClickListener? = null
private var onItemLongClickListener: OnRecyclerViewItemLongClickListener? = null
private val attachListener: RecyclerView.OnChildAttachStateChangeListener = object : RecyclerView.OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {
// every time a new child view is attached add click listeners to it
val holder = this#ItemClickSupport.recyclerView.getChildViewHolder(view)
.takeIf { it is ItemClickSupportViewHolder } as? ItemClickSupportViewHolder
if (onItemClickListener != null && holder?.isClickable != false) {
view.setOnClickListener(onClickListener)
}
if (onItemLongClickListener != null && holder?.isLongClickable != false) {
view.setOnLongClickListener(onLongClickListener)
}
}
override fun onChildViewDetachedFromWindow(view: View) {
}
}
init {
// the ID must be declared in XML, used to avoid
// replacing the ItemClickSupport without removing
// the old one from the RecyclerView
this.recyclerView.setTag(R.id.item_click_support, this)
this.recyclerView.addOnChildAttachStateChangeListener(attachListener)
}
companion object {
fun addTo(view: RecyclerView): ItemClickSupport {
// if there's already an ItemClickSupport attached
// to this RecyclerView do not replace it, use it
var support: ItemClickSupport? = view.getTag(R.id.item_click_support) as? ItemClickSupport
if (support == null) {
support = ItemClickSupport(view)
}
return support
}
fun removeFrom(view: RecyclerView): ItemClickSupport? {
val support = view.getTag(R.id.item_click_support) as? ItemClickSupport
support?.detach(view)
return support
}
}
private val onClickListener = View.OnClickListener { v ->
val listener = onItemClickListener ?: return#OnClickListener
// ask the RecyclerView for the viewHolder of this view.
// then use it to get the position for the adapter
val holder = this.recyclerView.getChildViewHolder(v)
listener.invoke(this.recyclerView, holder.adapterPosition, v)
}
private val onLongClickListener = View.OnLongClickListener { v ->
val listener = onItemLongClickListener ?: return#OnLongClickListener false
val holder = this.recyclerView.getChildViewHolder(v)
return#OnLongClickListener listener.invoke(this.recyclerView, holder.adapterPosition, v)
}
private fun detach(view: RecyclerView) {
view.removeOnChildAttachStateChangeListener(attachListener)
view.setTag(R.id.item_click_support, null)
}
fun onItemClick(listener: OnRecyclerViewItemClickListener?): ItemClickSupport {
onItemClickListener = listener
return this
}
fun onItemLongClick(listener: OnRecyclerViewItemLongClickListener?): ItemClickSupport {
onItemLongClickListener = listener
return this
}
}
/** Give click-ability and long-click-ability control to the ViewHolder */
interface ItemClickSupportViewHolder {
val isClickable: Boolean get() = true
val isLongClickable: Boolean get() = true
}
// Extension function
fun RecyclerView.addItemClickSupport(configuration: ItemClickSupport.() -> Unit = {}) = ItemClickSupport.addTo(this).apply(configuration)
fun RecyclerView.removeItemClickSupport() = ItemClickSupport.removeFrom(this)
fun RecyclerView.onItemClick(onClick: OnRecyclerViewItemClickListener) {
addItemClickSupport { onItemClick(onClick) }
}
fun RecyclerView.onItemLongClick(onLongClick: OnRecyclerViewItemLongClickListener) {
addItemClickSupport { onItemLongClick(onLongClick) }
}
(Remember you also need to add an XML file, see above this section)
Bonus feature of Kotlin version
Sometimes you do not want all the items of the RecyclerView to be clickable.
To handle this I've introduced the ItemClickSupportViewHolder interface that you can use on your ViewHolder to control which item is clickable.
Example:
class MyViewHolder(view): RecyclerView.ViewHolder(view), ItemClickSupportViewHolder {
override val isClickable: Boolean get() = false
override val isLongClickable: Boolean get() = false
}
Java
Usage:
ItemClickSupport.addTo(mRecyclerView)
.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// do it
}
});
(it also support long item click)
Implementation (comments added by me):
public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
// ask the RecyclerView for the viewHolder of this view.
// then use it to get the position for the adapter
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
return false;
}
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
#Override
public void onChildViewAttachedToWindow(View view) {
// every time a new child view is attached add click listeners to it
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}
#Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
// the ID must be declared in XML, used to avoid
// replacing the ItemClickSupport without removing
// the old one from the RecyclerView
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
// if there's already an ItemClickSupport attached
// to this RecyclerView do not replace it, use it
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}
public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
return this;
}
public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
return this;
}
private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(mAttachListener);
view.setTag(R.id.item_click_support, null);
}
public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View v);
}
public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}
How it works (why it's efficient)
This class works by attaching a RecyclerView.OnChildAttachStateChangeListener to the RecyclerView. This listener is notified every time a child is attached or detached from the RecyclerView. The code use this to append a tap/long click listener to the view. That listener ask the RecyclerView for the RecyclerView.ViewHolder which contains the position.
This is more efficient then other solutions because it avoid creating multiple listeners for each view and keep destroying and creating them while the RecyclerView is being scrolled.
You could also adapt the code to give you back the holder itself if you need more.
Final remark
Keep in mind that it's COMPLETELY fine to handle it in your adapter by setting on each view of your list a click listener, like other answer proposed.
It's just not the most efficient thing to do (you create a new listener every time you reuse a view) but it works and in most cases it's not an issue.
It is also a bit against separation of concerns cause it's not really the Job of the Adapter to delegate click events.
I like this way and I'm using it
Inside
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
Put
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false);
v.setOnClickListener(new MyOnClickListener());
And create this class anywhere you want it
class MyOnClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
int itemPosition = recyclerView.indexOfChild(v);
Log.e("Clicked and Position is ",String.valueOf(itemPosition));
}
}
I've read before that there is a better way but I like this way is easy and not complicated.
Android Recyclerview With onItemClickListener,
Why we cant try this is working like ListView only.
Source : Link
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
And Set this to RecyclerView:
recyclerView = (RecyclerView)rootView. findViewById(R.id.recyclerView);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
// TODO Handle item click
Log.e("#####",""+position);
}
})
);
Thanks to #marmor, I updated my answer.
I think it's a good solution to handle the onClick() in the ViewHolder class constructor and pass it to the parent class via OnItemClickListener interface.
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
private LayoutInflater layoutInflater;
private List<MyObject> items;
private AdapterView.OnItemClickListener onItemClickListener;
public MyAdapter(Context context, AdapterView.OnItemClickListener onItemClickListener, List<MyObject> items) {
layoutInflater = LayoutInflater.from(context);
this.items = items;
this.onItemClickListener = onItemClickListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.my_row_layout, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
MyObject item = items.get(position);
}
public MyObject getItem(int position) {
return items.get(position);
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView title;
private ImageView avatar;
public ViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
avatar = itemView.findViewById(R.id.avatar);
title.setOnClickListener(this);
avatar.setOnClickListener(this);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
//passing the clicked position to the parent class
onItemClickListener.onItemClick(null, view, getAdapterPosition(), view.getId());
}
}
}
Usage of adapter in other classes:
MyFragment.java
public class MyFragment extends Fragment implements AdapterView.OnItemClickListener {
private RecyclerView recycleview;
private MyAdapter adapter;
.
.
.
private void init(Context context) {
//passing this fragment as OnItemClickListener to the adapter
adapter = new MyAdapter(context, this, items);
recycleview.setAdapter(adapter);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//you can get the clicked item from the adapter using its position
MyObject item = adapter.getItem(position);
//you can also find out which view was clicked
switch (view.getId()) {
case R.id.title:
//title view was clicked
break;
case R.id.avatar:
//avatar view was clicked
break;
default:
//the whole row was clicked
}
}
}
> How RecyclerView is different from Listview?
One difference is that there is LayoutManager class with RecyclerView by which you can manage your RecyclerView like-
Horizontal or Vertical scrolling by LinearLayoutManager
GridLayout by GridLayoutManager
Staggered GridLayout by StaggeredGridLayoutManager
Like for horizontal scrolling for RecyclerView-
LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llm);
Guys use this code in Your main activity. Very Efficient Method
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list);
UsersAdapter adapter = new UsersAdapter(users, this);
recyclerView.setAdapter(adapter);
adapter.setOnCardClickListner(this);
Here is your Adapter class.
public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UserViewHolder> {
private ArrayList<User> mDataSet;
OnCardClickListner onCardClickListner;
public UsersAdapter(ArrayList<User> mDataSet) {
this.mDataSet = mDataSet;
}
#Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_row_layout, parent, false);
UserViewHolder userViewHolder = new UserViewHolder(v);
return userViewHolder;
}
#Override
public void onBindViewHolder(UserViewHolder holder, final int position) {
holder.name_entry.setText(mDataSet.get(position).getUser_name());
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onCardClickListner.OnCardClicked(v, position);
}
});
}
#Override
public int getItemCount() {
return mDataSet.size();
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public static class UserViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
TextView name_entry;
public UserViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.user_layout);
name_entry = (TextView) itemView.findViewById(R.id.name_entry);
}
}
public interface OnCardClickListner {
void OnCardClicked(View view, int position);
}
public void setOnCardClickListner(OnCardClickListner onCardClickListner) {
this.onCardClickListner = onCardClickListner;
}
}
After this you will get this override method in your activity.
#Override
public void OnCardClicked(View view, int position) {
Log.d("OnClick", "Card Position" + position);
}
How to put it all together example...
onClick() handling
Cursor - RecyclerView
ViewHolder types
public class OrderListCursorAdapter extends CursorRecyclerViewAdapter<OrderListCursorAdapter.ViewHolder> {
private static final String TAG = OrderListCursorAdapter.class.getSimpleName();
private static final int ID_VIEW_HOLDER_ACTUAL = 0;
private static final int ID_VIEW_HOLDER = 1;
public OrderListCursorAdapter(Context context, Cursor cursor) {
super(context, cursor);
}
public static class ViewHolderActual extends ViewHolder {
private static final String TAG = ViewHolderActual.class.getSimpleName();
protected IViewHolderClick listener;
protected Button button;
public ViewHolderActual(View v, IViewHolderClick listener) {
super(v, listener);
this.listener = listener;
button = (Button) v.findViewById(R.id.orderList_item_button);
button.setOnClickListener(this);
}
public void initFromData(OrderData data) {
Log.d(TAG, "><initFromData(data=" + data + ")");
orderId = data.getId();
vAddressStart.setText(data.getAddressStart());
vAddressEnd.setText(data.getAddressEnd());
}
#Override
public void onClick(View view) {
if (view instanceof Button) {
listener.onButtonClick((Button) view, getPosition(), this);
} else {
super.onClick(view);
}
}
public interface IViewHolderClick extends ViewHolder.IViewHolderClick {
public void onButtonClick(Button button, int position, ViewHolder viewHolder);
}
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private static final String TAG = ViewHolder.class.getSimpleName();
protected long orderId;
protected IViewHolderClick listener;
protected TextView vAddressStart;
protected TextView vAddressEnd;
protected TextView vStatus;
public ViewHolder(View v, IViewHolderClick listener) {
super(v);
this.listener = listener;
v.setOnClickListener(this);
vAddressStart = (TextView) v.findViewById(R.id.addressStart);
vAddressEnd = (TextView) v.findViewById(R.id.addressEnd);
vStatus = (TextView) v.findViewById(R.id.status);
}
public void initFromData(OrderData data) {
Log.d(TAG, "><initFromData(data=" + data + ")");
orderId = data.getId();
vAddressStart.setText(data.getAddressStart());
vAddressEnd.setText(data.getAddressEnd());
}
public long getOrderId() {
return orderId;
}
#Override
public void onClick(View view) {
listener.onCardClick(view, getPosition(), this);
}
public interface IViewHolderClick {
public void onCardClick(View view, int position, ViewHolder viewHolder);
}
}
#Override
public int getItemViewType(int position) {
return position == 0 ? ID_VIEW_HOLDER_ACTUAL : ID_VIEW_HOLDER;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")");
ViewHolder result;
switch (viewType) {
case ID_VIEW_HOLDER_ACTUAL: {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_actual, parent, false);
result = new ViewHolderActual(itemView, new ViewHolderActual.IViewHolderClick() {
#Override
public void onCardClick(View view, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
view.getContext().startActivity(intent);
}
#Override
public void onButtonClick(Button button, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onButtonClick(button=" + button + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(button.getContext(), OrderMapActivity.class);
intent.putExtra(OrderMapActivity.ARG_ORDER_ID, viewHolder.getOrderId());
button.getContext().startActivity(intent);
}
});
break;
}
case ID_VIEW_HOLDER:
default: {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
result = new ViewHolder(itemView, new ViewHolder.IViewHolderClick() {
#Override
public void onCardClick(View view, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
view.getContext().startActivity(intent);
}
});
break;
}
}
Log.d(TAG, "<<onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")= " + result);
return result;
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
Log.d(TAG, "><onBindViewHolder(viewHolder=" + viewHolder + ", cursor=" + cursor + ")");
final OrderData orderData = new OrderData(cursor);
viewHolder.initFromData(orderData);
}
}
Following up MLProgrammer-CiM's excellent RxJava solution
Consume / Observe clicks
Consumer<String> mClickConsumer = new Consumer<String>() {
#Override
public void accept(#NonNull String element) throws Exception {
Toast.makeText(getApplicationContext(), element +" was clicked", Toast.LENGTH_LONG).show();
}
};
ReactiveAdapter rxAdapter = new ReactiveAdapter();
rxAdapter.getPositionClicks().subscribe(mClickConsumer);
RxJava 2.+
Modify the original tl;dr as:
public Observable<String> getPositionClicks(){
return onClickSubject;
}
PublishSubject#asObservable() was removed. Just return the PublishSubject which is an Observable.
RecyclerView doesn't have an onItemClickListener because RecyclerView is responsible for recycling views (surprise!), so it's the responsibility of the view that is recycled to handle the click events it receives.
This actually makes it much easier to use, especially if you had items that can be clicked in multiple places.
Anyways, detecting click on a RecyclerView item is very easy. All you need to do is define an interface (if you're not using Kotlin, in which case you just pass in a lambda):
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private final Clicks clicks;
public MyAdapter(Clicks clicks) {
this.clicks = clicks;
}
private List<MyObject> items = Collections.emptyList();
public void updateData(List<MyObject> items) {
this.items = items;
notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
}
public interface Clicks {
void onItemSelected(MyObject myObject, int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private MyObject myObject;
public MyViewHolder(View view) {
super(view);
// bind views
view.setOnClickListener((v) -> {
int adapterPosition = getBindingAdapterPosition();
if(adapterPosition >= 0) {
clicks.onItemSelected(myObject, adapterPosition);
}
});
}
public void bind(MyObject myObject) {
this.myObject = myObject;
// bind data to views
}
}
}
Same code in Kotlin:
class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
private var items: List<MyObject> = Collections.emptyList()
fun updateData(items: List<MyObject>) {
this.items = items
notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
}
inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
private lateinit var myObject: MyObject
init {
// binds views
myView.onClick {
val adapterPosition = getBindingAdapterPosition()
if(adapterPosition >= 0) {
itemClicks.invoke(myObject, adapterPosition)
}
}
}
fun bind(myObject: MyObject) {
this.myObject = myObject
// bind data to views
}
}
}
Thing you DON'T need to do:
1.) you don't need to intercept touch events manually
2.) you don't need to mess around with child attach state change listeners
3.) you don't need PublishSubject/PublishRelay from RxJava
Just use a click listener.
As far as I understand MLProgrammer-CiM answer, simply it's possible to just do this:
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private ImageView image;
private TextView title;
private TextView price;
public MyViewHolder(View itemView) {
super(itemView);
image = (ImageView)itemView.findViewById(R.id.horizontal_list_image);
title = (TextView)itemView.findViewById(R.id.horizontal_list_title);
price = (TextView)itemView.findViewById(R.id.horizontal_list_price);
image.setOnClickListener(this);
title.setOnClickListener(this);
price.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Toast.makeText(context, "Item click nr: "+getLayoutPosition(), Toast.LENGTH_SHORT).show();
}
}
After reading #MLProgrammer-CiM's answer, here is my code:
class NormalViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
#Bind(R.id.card_item_normal)
CardView cardView;
public NormalViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
cardView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v instanceof CardView) {
// use getAdapterPosition() instead of getLayoutPosition()
int itemPosition = getAdapterPosition();
removeItem(itemPosition);
}
}
}
I have done this way, its very simple:
Just add 1 Line for Clicked RecyclerView position:
int position = getLayoutPosition()
Full code for ViewHolder class:
private class ChildViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public TextView txtView;
public ChildViewHolder(View itemView) {
super(itemView);
imageView= (ImageView)itemView.findViewById(R.id.imageView);
txtView= (TextView) itemView.findViewById(R.id.txtView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("RecyclerView Item Click Position", String.valueOf(getLayoutPosition()));
}
});
}
}
Hope this will help you.
I use this method to start an Intent from RecyclerView:
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
final MyClass myClass = mList.get(i);
viewHolder.txtViewTitle.setText(myclass.name);
...
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Intent detailIntent = new Intent(mContext, type.class);
detailIntent.putExtra("MyClass", myclass);
mContext.startActivity(detailIntent);
}
}
);
See my approach on this:
First declare an interface like this:
/**
* Interface used for delegating item click events in a {#link android.support.v7.widget.RecyclerView}
* Created by Alex on 11/28/2015.
*/
public interface OnRecyclerItemClickListener<T> {
/**
* Called when a click occurred inside a recyclerView item view
* #param view that was clicked
* #param position of the clicked view
* #param item the concrete data that is displayed through the clicked view
*/
void onItemClick(View view, int position, T item);
}
Then create the adapter:
public class CustomRecyclerAdapter extends RecyclerView.Adapter {
private class InternalClickListener implements View.OnClickListener{
#Override
public void onClick(View v) {
if(mRecyclerView != null && mItemClickListener != null){
// find the position of the item that was clicked
int position = mRecyclerView.getChildAdapterPosition(v);
Data data = getItem(position);
// notify the main listener
mItemClickListener.onItemClick(v, position, data);
}
}
}
private final OnRecyclerItemClickListener mItemClickListener;
private RecyclerView mRecyclerView;
private InternalClickListener mInternalClickListener;
/**
*
* #param itemClickListener used to trigger an item click event
*/
public PlayerListRecyclerAdapter(OnRecyclerItemClickListener itemClickListener){
mItemClickListener = itemClickListener;
mInternalClickListener = new InternalClickListener();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
v.setOnClickListener(mInternalClickListener);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// do your binding here
}
#Override
public int getItemCount() {
return mDataSet.size();
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
}
#Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
mRecyclerView = null;
}
public Data getItem(int position){
return mDataset.get(position);
}
}
And now let's see how to integrate this from a fragment:
public class TestFragment extends Fragment implements OnRecyclerItemClickListener<Data>{
private RecyclerView mRecyclerView;
#Override
public void onItemClick(View view, int position, Data item) {
// do something
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.test_fragment, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mRecyclerView = view.findViewById(idOfTheRecycler);
mRecyclerView .setAdapter(new CustomRecyclerAdapter(this));
}
If you want to add onClick() to the child view of items, for example, a button in item, I found that you can do it easily in onCreateViewHolder() of your own RecyclerView.Adapter just like this:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.cell, null);
Button btn = (Button) v.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do it
}
});
return new MyViewHolder(v);
}
i don't know whether it's a good way, but it works well. If anyone has a better idea, very glad to tell me and correct my answer! :)
Here is a way to implement it quite easily if you have a list of POJOs and want to retrieve one on click from outside the adapter.
In your adapter, create a listener for the click events and a method to set it:
public class MyAdapter extends RecyclerView.Adapter<SitesListAdapter.ViewHolder> {
...
private List<MyPojo> mMyPojos;
private static OnItemClickListener mOnItemClickListener;
...
public interface OnItemClickListener {
public void onItemClick(MyPojo pojo);
}
...
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
mOnItemClickListener = onItemClickListener;
}
...
}
In your ViewHolder, implement onClickListener and create a class member to temporarily store the POJO the view is presenting, that way (this is an example, creating a setter would be better):
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public MyPojo mCurrentPojo;
...
public ViewHolder(View view) {
super(v);
...
view.setOnClickListener(this); //You could set this on part of the layout too
}
...
#Override
public void onClick(View view) {
if(mOnItemClickListener != null && mCurrentPojo != null){
mOnItemClickListener.onItemClick(mCurrentPojo);
}
}
Back in your adapter, set the current POJO when the ViewHolder is bound (or to null if the current view doesn't have one):
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final MyPojo currentPojo = mMyPojos.get(position);
holder.mCurrentPojo = currentPojo;
...
That's it, now you can use it like this from your fragment/activity:
mMyAdapter.setOnItemClickListener(new mMyAdapter.OnItemClickListener() {
#Override
public void onItemClick(MyPojo pojo) {
//Do whatever you want with your pojo here
}
});
Yes you can
public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
//inflate the view
View view = LayoutInflator.from(parent.getContext()).inflate(R.layout.layoutID,null);
ViewHolder holder = new ViewHolder(view);
//here we can set onClicklistener
view.setOnClickListener(new View.OnClickListeener(){
public void onClick(View v)
{
//action
}
});
return holder;
This worked for me:
#Override
public void onBindViewHolder(PlacesListViewAdapter.ViewHolder holder, int position) {
----
----
----
// Set setOnClickListener(holder);
}
#Override
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
----
----
----
#Override
public void onClick(View view) {
// Use to get the item clicked getAdapterPosition()
}
}
Here you can handle multiple onclick see below code and it is very efficient
public class RVNewsAdapter extends RecyclerView.Adapter<RVNewsAdapter.FeedHolder> {
private Context context;
List<News> newsList;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
public RVNewsAdapter(List<News> newsList, Context context) {
this.newsList = newsList;
this.context = context;
}
public static class FeedHolder extends RecyclerView.ViewHolder implements OnClickListener {
ImageView img_main;
TextView tv_title;
Button bt_facebook, bt_twitter, bt_share, bt_comment;
public FeedHolder(View itemView) {
super(itemView);
img_main = (ImageView) itemView.findViewById(R.id.img_main);
tv_title = (TextView) itemView.findViewById(R.id.tv_title);
bt_facebook = (Button) itemView.findViewById(R.id.bt_facebook);
bt_twitter = (Button) itemView.findViewById(R.id.bt_twitter);
bt_share = (Button) itemView.findViewById(R.id.bt_share);
bt_comment = (Button) itemView.findViewById(R.id.bt_comment);
img_main.setOnClickListener(this);
bt_facebook.setOnClickListener(this);
bt_twitter.setOnClickListener(this);
bt_comment.setOnClickListener(this);
bt_share.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v.getId() == bt_comment.getId()) {
Toast.makeText(v.getContext(), "Comment " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_facebook.getId()) {
Toast.makeText(v.getContext(), "Facebook " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_twitter.getId()) {
Toast.makeText(v.getContext(), "Twitter " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_share.getId()) {
Toast.makeText(v.getContext(), "share " , Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(v.getContext(), "ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public FeedHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_row, parent, false);
FeedHolder feedHolder = new FeedHolder(view);
return feedHolder;
}
#Override
public void onBindViewHolder(FeedHolder holder, int position) {
holder.tv_title.setText(newsList.get(position).getTitle());
// Here you apply the animation when the view is bound
setAnimation(holder.img_main, position);
}
#Override
public int getItemCount() {
return newsList.size();
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
}
Modified my comment...
public class MyViewHolder extends RecyclerView.ViewHolder {
private Context mContext;
public MyViewHolder(View itemView) {
super(itemView);
mContext = itemView.getContext();
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int itemPosition = getLayoutPosition();
Toast.makeText(mContext, "" + itemPosition, Toast.LENGTH_SHORT).show();
}
});
}
Check this one in which I have implemented all the things with a proper way
RecyclerViewHolder Class
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
//view holder is for girdview as we used in the listView
public ImageView imageView,imageView2;
public RecyclerViewHolder(View itemView) {
super(itemView);
this.imageView=(ImageView)itemView.findViewById(R.id.image);
}
}
Adapter
public class RecyclerView_Adapter extends RecyclerView.Adapter<RecyclerViewHolder> {
//RecyclerView will extend to recayclerview Adapter
private ArrayList<ModelClass> arrayList;
private Context context;
private static RecyclerViewClickListener itemListener;
//constructor of the RecyclerView Adapter
RecyclerView_Adapter(Context context,ArrayList<ModelClass> arrayList,RecyclerViewClickListener itemListener){
this.context=context;
this.arrayList=arrayList;
this.itemListener=itemListener;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//this method will inflate the custom layout and return as viewHolder
LayoutInflater layoutInflater=LayoutInflater.from(parent.getContext());
ViewGroup mainGroup=(ViewGroup) layoutInflater.inflate(R.layout.single_item,parent,false);
RecyclerViewHolder listHolder=new RecyclerViewHolder(mainGroup);
return listHolder;
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
final ModelClass modelClass=arrayList.get(position);
//holder
RecyclerViewHolder mainHolder=(RecyclerViewHolder)holder;
//convert the drawable image into bitmap
Bitmap image= BitmapFactory.decodeResource(context.getResources(),modelClass.getImage());
//set the image into imageView
mainHolder.imageView.setImageBitmap(image);
//to handle on click event when clicked on the recyclerview item and
// get it through the RecyclerViewHolder class we have defined the views there
mainHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//get the position of the image which is clicked
itemListener.recyclerViewListClicked(v,position);
}
});
}
#Override
public int getItemCount() {
return (null!=arrayList?arrayList.size():0);
}
}
The interface
public interface RecyclerViewClickListener {
//this is method to handle the event when clicked on the image in Recyclerview
public void recyclerViewListClicked(View v,int position);
}
//and to call this method in activity
RecyclerView_Adapter adapter=new RecyclerView_Adapter(Wallpaper.this,arrayList,this);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
#Override
public void recyclerViewListClicked(View v,int position){
imageView.setImageResource(wallpaperImages[position]);
}
Access the mainView of rowLayout(cell) for you RecyclerView and in your OnBindViewHolder write this code:
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
Movie movie = moviesList.get(position);
holder.mainView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.out.println("pos " + position);
}
});
}
it worked for me. Hope it will help. Most simplest way.
Inside View Holder
class GeneralViewHolder extends RecyclerView.ViewHolder {
View cachedView = null;
public GeneralViewHolder(View itemView) {
super(itemView);
cachedView = itemView;
}
Inside OnBindViewHolder()
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final GeneralViewHolder generalViewHolder = (GeneralViewHolder) holder;
generalViewHolder.cachedView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "item Clicked at "+position, Toast.LENGTH_SHORT).show();
}
});
And let me know, do you have any question about this solution ?
main_recyclerview.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
int position=rv.getChildAdapterPosition(rv.findChildViewUnder(e.getX(),e.getY()));
switch (position)
{
case 0:
{
wifi(position);
adapter2.notifyDataSetChanged();
}
break;
case 1:
{
sound(position);
adapter2.notifyDataSetChanged();
}
break;
case 2:
{
bluetooth(position);
adapter2.notifyDataSetChanged();
}
break;
}
return true;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e)
{
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
Instead of implementing interface View.OnClickListener inside view holder or creating and interface and implementing interface in your activity..
I used this code for simple on OnClickListener implementation.
public static class SimpleStringRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {
// Your initializations goes here...
private List<String> mValues;
public static class ViewHolder extends RecyclerView.ViewHolder {
//create a variable mView
public final View mView;
/*All your row widgets goes here
public final ImageView mImageView;
public final TextView mTextView;*/
public ViewHolder(View view) {
super(view);
//Initialize it here
mView = view;
/* your row widgets initializations goes here
mImageView = (ImageView) view.findViewById(R.id.avatar);
mTextView = (TextView) view.findViewById(android.R.id.text1);*/
}
}
public String getValueAt(int position) {
return mValues.get(position);
}
public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {
mBackground = mTypedValue.resourceId;
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
view.setBackgroundResource(mBackground);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mBoundString = mValues.get(position);
holder.mTextView.setText(mValues.get(position));
//Here it is simply write onItemClick listener here
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(context, ExampleActivity.class);
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
}
use PlaceHolderView
#Layout(R.layout.item_view_1)
public class View1{
#View(R.id.txt)
public TextView txt;
#Resolve
public void onResolved() {
txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
}
#Click(R.id.btn)
public void onClick(){
txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
}
}
I wrote a library to handle android recycler view item click event. You can find whole tutorial in https://github.com/ChathuraHettiarachchi/RecycleClick
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
}
});
or to handle item long press you can use
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() {
#Override
public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
return true;
}
});
recyclerview animation has not been tested, the other is normal. I think it has been optimized to the maximum. Interface has other uses, you can temporarily ignore.
public abstract class BaseAdapterRV<VH extends BaseViewHolder> extends RecyclerView.Adapter<VH> implements AdapterInterface {
public final String TAG = getClass().getSimpleName();
protected final Activity mActivity;
protected final LayoutInflater mInflater;
protected ItemClickInterface<?, Integer> mListener;
public BaseAdapterRV(Activity activity) {
mActivity = activity;
mInflater = LayoutInflater.from(mActivity);
}
#Override
public final VH onCreateViewHolder(ViewGroup parent, int viewType) {
return onCreateViewHolder(parent, viewType, mInflater);
}
#Override
public final void onBindViewHolder(VH holder, int position) {
holder.itemView.setTag(R.id.tag_view_click, position);
//创建点击事件
holder.itemView.setOnClickListener(mListener);
holder.itemView.setOnLongClickListener(mListener);
onBindVH(holder, position);
}
///////////////////////////////////////////////////////////////////////////
// 以下是增加的方法
///////////////////////////////////////////////////////////////////////////
/**
* 注意!涉及到notifyItemInserted刷新时立即获取position可能会不正确
* 里面也有onItemLongClick
*/
public void setOnItemClickListener(ItemClickInterface<?, Integer> listener) {
mListener = listener;
notifyDataSetChanged();
}
#NonNull
protected abstract VH onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater);
protected abstract void onBindVH(VH holder, int position);
}
This is Interface
/**
* OnItemClickListener的接口
* 见子类实现{#link OnItemClickListener}{#link OnItemItemClickListener}
*/
public interface ItemClickInterface<DATA1, DATA2> extends View.OnClickListener, View.OnLongClickListener {
void onItemClick(DATA1 data1, DATA2 data2);
boolean onItemLongClick(DATA1 data1, DATA2 data2);
}
This is an abstract class
public abstract class OnItemClickListener<DATA> implements ItemClickInterface<View, DATA> {
#Override
public void onClick(View v) {
onItemClick(v, (DATA) v.getTag(R.id.tag_view_click));
}
#Override
public boolean onLongClick(View v) {
return onItemLongClick(v, (DATA) v.getTag(R.id.tag_view_click));
}
#Override
public boolean onItemLongClick(View view, DATA data) {
return false;
}
}
You only need it
mAdapter.setOnItemClickListener(new OnItemClickListener<Integer>() {
#Override
public void onItemClick(View view, Integer integer) {
}
#Override
public boolean onItemLongClick(View view, Integer integer) {
return true;
}
});
I found one of the shortest ways using androidx lifecycle mutable live data
Adapter:
private val onItemClickListener = MutableLiveData<YourAdapterItem>()
override fun onBindViewHolder(holder: GifsViewHolder, position: Int) {
holder.itemView.setOnClickListener { onItemClickListener.value = gifs[position] }
}
fun getOnItemClickListener(): MutableLiveData<Gif> {
return onItemClickListener
}
anywhere in MainActivity
yourFancyAdapter.getOnItemClickListener().observe(this, Observer {
println(it)
})

Categories

Resources