Android Button Click Event is fired multiple times in implemeting a recycler view with search filter?

Viewed 1119

I am working in Xamarin Android. I have implemented a recycler view with list of patients. I have also implemented a search view to filter the list of patients searched. I have a button click event inside the OnBindViewHolder which becomes called multiple times, whenever I implement a search as the list gets updated. If I dont filter patients, the button is initialized only once so, I have no problem in that. But if I perform a search filter the button becomes initialized again and again so whenever I click a button I go into another activity "NewActivity" multiple times. How can I solve this? The "populateRecyclerView" will be called after running a query which I have not mentioned here.

My RecylerAdapter.cs

public class PatientRecyclerAdapter : RecyclerView.Adapter
{
    private Context context;
    private List<Patient> patientList, filteredPatientList;
    public event EventHandler<CheckInClickArgs> CheckInClicked;
    MyHolder myholder;

    public class CheckInClickArgs : EventArgs
    {
        public Patient selectedPatient { get; set; }
    }

    public PatientRecyclerAdapter(Context context, List<Patient> patientList)
    {
        this.context = context;
        this.patientList = patientList;
        this.filteredPatientList = patientList;
    }

    public override int ItemCount
    {
        get { return filteredPatientList.Count; }
    }

    public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        myholder = (MyHolder)holder;
        Patient patient = filteredPatientList[position];
        myholder.tvPatientName.Text = patient.Fullname;
            myholder.btnCheckIn.Click += (sender, e) =>
            {
                if (CheckInClicked != null)
                {
                    CheckInClicked(this, new CheckInClickArgs { selectedPatient = patient });
                }       
        }

    public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
    {
        View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.layout_patientCardViewRecyler, parent, false);
        MyHolder holder = new MyHolder(view);
        return holder;
    }

    public void filter(string searchText)
    {
        searchText = searchText.ToLower();
        this.filteredPatientList = patientList.Where(x => x.Fullname.ToLower().Contains(searchText)).ToList();
    }
}

class MyHolder : RecyclerView.ViewHolder
{
    public TextView tvPatientName;
    public Button btnCheckIn;
    public MyHolder(View itemView) : base(itemView)
    {
        tvPatientName = itemView.FindViewById<TextView>(Resource.Id.textViewPatientName);
        btnCheckIn = itemView.FindViewById<Button>(Resource.Id.btnCheckIn);
    }
}

PatientsTabFragment.cs

public class PatientsTabFragment : Android.Support.V4.App.Fragment, ITextWatcher, TextView.IOnEditorActionListener
{
    private Android.Views.View view;
    private RecyclerView recyclerView;
    private RecyclerView.LayoutManager recyclerview_layoutmanager;
    private PatientRecyclerAdapter recyclerview_adapter;
    private EditText etSearchView;

    public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        view = inflater.Inflate(Resource.Layout.fragment_patients_tab, container, false);
        etSearchView = view.FindViewById<EditText>(Resource.Id.etSearchView);
        return view;
    }

   void populateRecyclerView(List<Patient> patient)
        {
        recyclerView = view.FindViewById<RecyclerView>(Resource.Id.recyclerViewPatient);
        recyclerview_layoutmanager = new LinearLayoutManager(this.Activity, LinearLayoutManager.Vertical, false);
        recyclerView.SetLayoutManager(recyclerview_layoutmanager);

        recyclerview_adapter = new PatientRecyclerAdapter(this.Activity, patient);
        recyclerView.SetAdapter(recyclerview_adapter);
        etSearchView.AddTextChangedListener(this);
        recyclerview_adapter.CheckInClicked += (sender, e) =>
        {
            AppController.SelectedPatient = e.selectedPatient;
            Activity.StartActivity(typeof(NewActivity));
        };
    }

    public void OnTextChanged(ICharSequence s, int start, int before, int count)
    {
        recyclerview_adapter.filter(s.ToString());
        recyclerview_adapter.NotifyDataSetChanged();
    }
1 Answers

On your Bind you have set your click this way. this is set only click

so change you this code

myholder.btnCheckIn.Click += (sender, e) =>
            {
                if (CheckInClicked != null)
                {
                    CheckInClicked(this, new CheckInClickArgs { selectedPatient = patient });
                }

to this

if(!myholder.btnCheckIn.HasOnClickListeners)
{
        myholder.btnCheckIn.Click += (sender, e) =>
                {
                    if (CheckInClicked != null)
                    {
                        CheckInClicked(this, new CheckInClickArgs { selectedPatient = patient });
                    }
                }
}

EDIT :

change your this code because the problem is in your position. you have to set Adapter Position which will give the correct position of Button Click see below code.

myholder = (MyHolder)holder;
Patient patient = filteredPatientList[myholder.AdapterPosition];
myholder.tvPatientName.Text = patient.Fullname;
Related