Search code examples
androidinterfaceandroid-recyclerviewadapterandroid-dialogfragment

How to perform this date update on my RecyclerView rows?


In my RecyclerView adapter, my rows have TextViews that display dates. If the user clicks the TextView, a DialogFragment is displayed that lets the user pick a time and date, and then a Date is passed back through an interface.

However I don't know how to grab the date back in the onClick method I added to my TextView.

public class RecyclerViewHolder extends RecyclerView.ViewHolder {
        public TextView dateTextView;
        public RecyclerViewHolder(View itemView) {
            super(itemView);
            dateTextView = (TextView) itemView.findViewById(R.id.date_textview);

            dateTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //I can call my DialogFragment here but then what?
                }
            });

Solution

  • You can create an interface to communicate with adapter:

    public class RecyclerViewHolder extends RecyclerView.ViewHolder {
    
        public TextView dateTextView;
        private IAdapter adapter;
    
        public RecyclerViewHolder(View itemView, IAdapter adapter) {
            super(itemView);
            dateTextView = (TextView) itemView.findViewById(R.id.date_textview);
            this.adapter = adapter;
    
            dateTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    MyDialogFragment fragment = MyDialogFragment.newInstance(getAdapterPosition(), adapter);
                    FragmentTransaction ft = v.getContext().getFragmentManager().beginTransaction();
                    fragment.show(ft, "calendarDialog");
                }
            });
        }
    }
    

    The interface which the adapter will need to implement is:

    interface IAdapter extends Serializable {
        void setDataAt(int index, Calendar date);
        void notifyItemChanged(int index);
    }
    

    Since adapter already has the notifyItemChanged method, you will only need to implement the setDataAt method.

    Assuming that your Adapter will only contain dates, here is an example:

    public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> implements IAdapter {
    
        private List<Calendar> dates = new ArrayList<>();
    
        public RecyclerViewAdapter(List<Calendar> dates) {
            this.dates = dates;
        }
    
        @Override
        public void setDataAt(int index, Calendar date) {
            dates.add(index, date);
        }
    
        @Override
        public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            View holderView = inflater.inflate(R.layout.view_holder, parent, false);
            return new RecyclerViewHolder(holderView, this); // notice how we pass this adapter's interface along with the view
        }
    
        // Include other methods (getItemCount, onBindViewHolder, etc.)
        // Adapter already has the notifyItemChanged(int index) method so no need to override it
    }
    

    Here is an example of a DialogFragment that uses the index position and a Calendar object:

    public static class MyDialogFragment extends DialogFragment {
        private int index;
        private IAdapter adapter;
    
    
        public static MyDialogFragment newInstance(int index, IAdapter adapter) {
            MyDialogFragment f = new MyDialogFragment();
    
            Bundle args = new Bundle();
            args.putInt("index", index);
            args.putSerializable("adapter", adapter);
            f.setArguments(args);
    
            return f;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Bundle args = getArguments();
            index = args.getInt("index");
            adapter = args.getSerializable("adapter");
        }
    
        // Build view and set OnClickListener for setting date
    }
    

    After the user updates the date, invoke the following:

    adapter.setDataAt(index, date);
    adapter.notifyItemChanged(index);