0

I have a fragment that holds a recyclerview which has a staggered grid layout manager for which the view holder just has an image. I am trying to make it such that after a menu option (delete icon) is selected an onItemClickListener is enabled for the recyclerView so that images can be deleted just by tapping on them. Additionally, I have it such that the delete icon is replaced by a stop icon to then disable the onItemClickListener. I am having trouble getting the onItemClickListener to execute the code pertaining to deletion once the after the menu item is selected, however when this code is just in the onCreateView method of the Fragment the onItemClickListener works just fine.

Here is the code for the ViewHolder and onClick interface in my adapter class:

public class PhotoListViewHolder extends RecyclerView.ViewHolder {

        SquareImageView imageView;

        public PhotoListViewHolder (@NonNull View itemView, OnItemClickListener listener) {
            super(itemView);

            imageView = itemView.findViewById(R.id.image);

            itemView.setOnClickListener(v -> {
                if (listener != null) {
                    int position = getAdapterPosition();
                    if (position != RecyclerView.NO_POSITION) {

                        listener.onItemClick(position);
                    }
                }
            });
        }

    }
public interface OnItemClickListener {
        void onItemClick(int position);

    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

    public OnItemClickListener getListener() {
        return listener;
    }

and here is the code for the handling of the menu items and how things are deleted in the Fragment

@Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {

        switch(item.getItemId()) {

            case R.id.delete_items:
                Toast.makeText(getContext(), "Tap an image to delete it", Toast.LENGTH_SHORT).show();
                adapter.setOnItemClickListener(this);
                Log.d(TAG, "start-" + adapter.getListener());
                deleteItem.setVisible(false);
                stopDelete.setVisible(true);
                return true;

            case R.id.stop_selection:

                adapter.setOnItemClickListener(null);
                Log.d(TAG, "stop-" + adapter.getListener());
                currDelete = END_DELETE;
                stopDelete.setVisible(false);
                deleteItem.setVisible(true);

                return true;
            default:
                return super.onOptionsItemSelected(item);
        }

    }
@Override
    public void onItemClick(int position) {
        delete(position);
    }

Logic for deletion:

 private void delete(int position) {

        Log.d(TAG, "delete: " + position);
        photoList.removePhoto(position);
        adapter.notifyDataSetChanged();
        savePhotos();
    }

as I said, when just starting the onItemClickListener in the onCreateView method of the fragment, the image deletes fine, however when "dynamically" doing it, it does not work even though the onItemClickListener is being created and destroyed as seen by this log:

2020-05-01 12:51:32.518 8719-8777/com.streetxportrait.android.planrr D/EGL_emulation: eglMakeCurrent: 0xd8e1a240: ver 3 0 (tinfo 0xd8e0f1c0)
2020-05-01 12:51:32.531 8719-8777/com.streetxportrait.android.planrr D/EGL_emulation: eglMakeCurrent: 0xd8e1a240: ver 3 0 (tinfo 0xd8e0f1c0)
2020-05-01 12:51:52.869 8719-8719/com.streetxportrait.android.planrr D/Grid-fragments: stop-null
2020-05-01 12:58:41.889 8719-8719/com.streetxportrait.android.planrr D/Grid-fragments: start-GridFragment{5a15f1} (3a58a131-1b5e-4fd5-8369-754fb2750bf8) id=0x7f080141 android:switcher:2131231041:0}
2020-05-01 12:58:41.929 8719-8777/com.streetxportrait.android.planrr D/EGL_emulation: eglMakeCurrent: 0xd8e1a240: ver 3 0 (tinfo 0xd8e0f1c0)
2020-05-01 12:58:41.936 8719-8777/com.streetxportrait.android.planrr D/EGL_emulation: eglMakeCurrent: 0xd8e1a240: ver 3 0 (tinfo 0xd8e0f1c0)
2020-05-01 12:58:52.868 8719-8719/com.streetxportrait.android.planrr D/Grid-fragments: stop-null

I also tried enabling and disabling the listener through a regular button within the view, as well as by doing it asynchronously, however neither of those worked either.

here is the code for the async attempt:

 private void testWhatever() {


        AsyncTask.execute(() -> {
            while (true) {
                Log.d(TAG, "testWhatever: Current: " + currDelete);

                if (currDelete == START_DELETE) {
                    adapter.setOnItemClickListener(this);
                    Log.d(TAG, "testWhatever: start-" + adapter.getListener());
                }
                else if (currDelete == END_DELETE) {
                    adapter.setOnItemClickListener(null);
                    Log.d(TAG, "testWhatever: stop-" + adapter.getListener());
                }

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

Is it not possible to enable and disable onClickListeners dynamically? Or does anyone know what's happening here?

1 Answers1

0

Under the fragment's onCreate() call setHasOptionsMenu(true) to notify the framework that the fragment would like to process the options menu.

codeman
  • 144
  • 7
  • Sorry, forgot to mention that I've already done that. The menu items and everything show up fine, it's just the clicking on items that does not work. – cs_pool_besty May 01 '20 at 19:57
  • 1
    Then I suspect the problem is due to a variable reference issue resulting from the way you are setting the itemview onCLickListener in the viewholder constructor. Try setting the itemview click listener under the onBind() method. – codeman May 01 '20 at 21:19
  • Do you mean in the onBindViewHolder method in the main adapter class? Or should i make a new method called onBind in the viewHolder class? – cs_pool_besty May 01 '20 at 22:03
  • 1
    Yes under the onBindViewMethod and reference the OnItemClickListener directly. In Java you cannot change the value of an object reference passed in as arguments to a method. Which means in your case the itemview onClickListeners will continue to reference the value initially passed to the viewholder constructor (which is null) even if you later change the value of the original OnItemClickLister reference. The issue is a subtle but important one. Check this thread which deals with this issue: https://stackoverflow.com/a/40501/10766098 – codeman May 02 '20 at 07:40