0

My fragment has a Recycler View. Therefore I have a RecyclerView Adapter too. From this Adapter, I am opening an AlertDialog. When I click OK, I need to pass the onclick event from my DialogFragment back to my RecyclerView Adapter.

Currently, I am doing it like here, but this passes the event back to the activity and not to the RecyclerView Adapter.

public class FreshwaterRecyclerViewAdapter extends RecyclerView.Adapter<FreshwaterRecyclerViewAdapter.ViewHolder> implements BiotopeDialogFragment.NoticeDialogListener {
    private List<Biotope> data;
    private LayoutInflater layoutInflater;

    FreshwaterRecyclerViewAdapter(Context context, List<Biotope> data) {
        this.layoutInflater = LayoutInflater.from(context);
        this.data = data;
    }

    //The dialog fragment receives a reference to this Activity through the
    //Fragment.onAttach() callback, which it uses to call the following methods
    //defined by the NoticeDialogFragment.NoticeDialogListener interface
    @Override
    public void onDialogPositiveClick(DialogFragment dialog) {
        notifyItemInserted(getItemCount()-1);
    }

    @Override
    public void onDialogNegativeClick(DialogFragment dialog) {

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView;
        if (viewType == R.layout.biotope_cardview){
            itemView = layoutInflater.inflate(R.layout.biotope_cardview, parent, false);
        } else {
            itemView = layoutInflater.inflate(R.layout.biotope_add_button, parent, false);
        }

        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        if (position == data.size()) {
            holder.imageButtonAddBiotope.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    FragmentManager fragmentManager = ((AppCompatActivity) layoutInflater.getContext()).getSupportFragmentManager();
                    DialogFragment dialog = new BiotopeDialogFragment();
                    dialog.show(fragmentManager, "NoticeDialogFragment");
                }
            });
        } else {
            holder.textViewBiotopeTitle.setText(getItem(position).name);
        Picasso.get().load(Uri.parse(getItem(position).imageUri)).into(holder.imageViewBiotope);

            LastValuesRecyclerViewAdapter recyclerAdapter = new LastValuesRecyclerViewAdapter(layoutInflater.getContext(), getData());
            holder.recyclerViewLastValues.setLayoutManager(new LinearLayoutManager(layoutInflater.getContext(), LinearLayoutManager.HORIZONTAL, false));
            holder.recyclerViewLastValues.setAdapter(recyclerAdapter);
        }
    }

    //total number of rows
    @Override
    public int getItemCount() {
        return data.size() + 1;     //+1 for the add button
    }

    @Override
    public int getItemViewType(int position) {
        return (position == data.size()) ? R.layout.biotope_add_button : R.layout.biotope_cardview;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private TextView textViewBiotopeTitle;
        private ImageView imageViewBiotope;
        private RecyclerView recyclerViewLastValues;
        private ImageButton imageButtonAddBiotope;

        public ViewHolder(View view) {
            super(view);
            textViewBiotopeTitle = (TextView) view.findViewById(R.id.textViewBiotopeTitle);
            imageViewBiotope = (ImageView) view.findViewById(R.id.imageViewBiotopeCardview);
            recyclerViewLastValues = (RecyclerView) view.findViewById(R.id.recyclerViewLastValues);
            imageButtonAddBiotope = (ImageButton) view.findViewById(R.id.imageButtonAddBiotope);
        }
    }

    Biotope getItem(int id) {
        return data.get(id);
    }

    private List<String> getData() {
        List<String> data = new ArrayList<>();

        data.add("PO4");
        data.add("NO3");

        return data;
    }

}

This is my dialog.

public class BiotopeDialogFragment extends DialogFragment {

    private NoticeDialogListener listener;
    public interface NoticeDialogListener {
        public void onDialogPositiveClick(DialogFragment dialog);
        public void onDialogNegativeClick(DialogFragment dialog);
    }

    //Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);

        //Verify that the host activity implements the callback interface
        try {
            //Instantiate the NoticeDialogListener so we can send events to the host
            listener = (NoticeDialogListener) context;
        } catch (ClassCastException e) {
            //The activity doesn't implement the interface, throw exception
            throw new ClassCastException("FreshwaterRecyclerViewAdapter must implement NoticeDialogListener | Context: " + context.toString());
        }
    }

    public static final String TAG = "biotope_dialog_fragment";

    private ActivityResultLauncher<Intent> activityResultLauncher;

    private Uri imageUri = null;

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext());
        LayoutInflater inflater = requireActivity().getLayoutInflater();

        //Inflate and set the layout for the dialog
        //Pass null as the parent view because its going in the dialog layout
        View view = inflater.inflate(R.layout.fragment_dialog_biotope, null, false);
        builder.setView(view);

        View colorPickerPreviewView = view.findViewById(R.id.colorPickerPreviewView);
        ColorPickerView colorPickerView = view.findViewById(R.id.colorPickerView);
        ImageView imageViewBiotope = view.findViewById(R.id.imageViewBiotopePreview);
        TextInputEditText textFieldBiotopeName = view.findViewById(R.id.textFieldBiotopeName);

        builder.setTitle("New biotope")
                .setPositiveButton("ok", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                        BiotopeDatabase database = BiotopeDatabase.getDbInstance(requireContext().getApplicationContext());

                        Biotope biotope = new Biotope();
                        if (textFieldBiotopeName.getText() != null) {
                            biotope.name = textFieldBiotopeName.getText().toString();
                        } else {
                            biotope.name = "";
                        }

                        if (imageUri != null) {
                            biotope.imageUri = imageUri.toString();
                        } else {
                            biotope.imageUri = "";
                        }

                        biotope.color = colorPickerView.getColor();

                        database.biotopeDao().insertAll(biotope);

                        //Send the positive button event back to the host activity
                        listener.onDialogPositiveClick(BiotopeDialogFragment.this);
                    }
                })
                .setNegativeButton("noke", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        //Send the negative button event back to the host activity
                        listener.onDialogNegativeClick(BiotopeDialogFragment.this);

                        Objects.requireNonNull(BiotopeDialogFragment.this.getDialog()).cancel();
                    }
                });


        return builder.create();
    }

    public static BiotopeDialogFragment display(FragmentManager fragmentManager) {
        BiotopeDialogFragment fragment = new BiotopeDialogFragment();
        fragment.show(fragmentManager, TAG);
        return fragment;
    }

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

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }

}

This is my fragment building the RecyclerView. Alternatively, I can pass the event back to the fragment if it is not possible to pass it to the adapter.

public class BiotopesFragment extends Fragment {
    private FreshwaterRecyclerViewAdapter recyclerAdapter;

    public static BiotopesFragment newInstance(String param1, String param2) {
        BiotopesFragment fragment = new BiotopesFragment();
        return fragment;
    }

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

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

        RecyclerView recyclerViewFreshwater = (RecyclerView) root.findViewById(R.id.recyclerViewFreshwater);
        recyclerAdapter = new FreshwaterRecyclerViewAdapter(getContext(), getData());
        recyclerViewFreshwater.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
        recyclerViewFreshwater.setAdapter(recyclerAdapter);

        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
        recyclerViewFreshwater.addItemDecoration(dividerItemDecoration);

        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.START | ItemTouchHelper.END, 0) {
            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
                int fromPosition = viewHolder.getAdapterPosition();
                int toPosition = target.getAdapterPosition();
                Collections.swap(getData(), fromPosition, toPosition);
                recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
                return false;
            }

            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {

            }
        });
        itemTouchHelper.attachToRecyclerView(recyclerViewFreshwater);

        return root;
    }

    private List<Biotope> getData() {
        BiotopeDatabase database = BiotopeDatabase.getDbInstance(requireContext().getApplicationContext());
        BiotopeDao biotopeDao = database.biotopeDao();
        return biotopeDao.getAll();
    }

}
Pezcraft
  • 270
  • 3
  • 15
  • 1
    `I need to pass the onclick event from my DialogFragment back to my RecyclerView Adapter.` this doesn't sound correct, your adapter shouldn't be creating any dialogs, it should make use of a callback to your fragment so that the fragment opens a dialog and then the feedback from the dialog can go to the fragment, not back to the adapter – a_local_nobody Mar 29 '22 at 11:46

1 Answers1

1

Ideal Way to do this to create all UI component in Fragment not in the adapter . Create an interface to handle events in the fragment and provide callback to the fragment from adapter. now your Fragment should create all the UI component .

Now coming to the

How to provide callback from dialog fragment to Fragment.

You can use setTargetFragment but its deprecated . Now you can use setFragmentResultListener instead of setTargetFragment(), its the safest way i think. Once you get the result back in fragment you can call any method of your adapter.

ADM
  • 20,406
  • 11
  • 52
  • 83