简体   繁体   中英

Passing events from DialogFragment back to RecyclerView Adapter

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();
    }

}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM