skip to Main Content

I have a RecyclerView populated with objects and inside of my RecyclerView adapter I have a function for renaming the name value of the object, when running this method I use getBindingAdapterPosition() to get the selected object from the ArrayList of task objects to rename it, however getBindingAdapterPosition() is returning RecyclerView.NO_POSITION (or -1) only on SOME items in the RecyclerView and on others the function is working properly, I do not know why this is happening and I have tried to battle it by using an if check to check if getBindingAdapterPosition() is equal to RecyclerView.NO_POSITION but that check does not solve the issue it only skips the renaming. I also tried by adding adapter.notifyItemChanged(adapterPosition) thinking that maybe it didn’t work because the adapter wasn’t being notified of the change, but the issue persists. Why is getBindingAdapterPosition() returning -1 only on SOME items and how can I solve this? Is there another method I can use or is there something I am doing wrong without noticing?

Here is the MyViewHolder in my RecyclerViewAdapter class:

public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
    TextView textView;
    OnItemListener onItemListener;
    ArrayList<Task> list;
    private final RecyclerViewAdapter adapter;

    MyViewHolder(@NonNull View itemView, OnItemListener onItemListener, ArrayList<Task> list, RecyclerViewAdapter adapter) {
        super(itemView);

        textView = itemView.findViewById(R.id.singleView);
        this.onItemListener = onItemListener;
        this.list = list;
        this.adapter = adapter;

        itemView.setOnClickListener(this);
        itemView.setOnLongClickListener(view -> {
            onLongClick();
            return true;
        });
    }

    private void onLongClick(int position)
    {
        // Handles the long click event on an item in the RecyclerView,
        // opens a Dialog with an EditText with the name of the task to edit the task name.

        String text = textView.getText().toString();
        // Creates the EditText for user input and style the look and behavior of it.
        final EditText input = new EditText(itemView.getContext());
        input.setBackground(ContextCompat.getDrawable(itemView.getContext(), R.drawable.edit_text_dialog));
        input.setTextColor(ContextCompat.getColor(itemView.getContext(), R.color.colorText));
        input.setText(text);
        input.setSingleLine();
        input.setImeOptions(EditorInfo.IME_ACTION_SEND);
        input.setPadding(28, 28, 28, 28);

        // Create an AlertDialog for the user to edit the task name.
        AlertDialog.Builder builder = new AlertDialog.Builder(itemView.getContext(), R.style.DialogTheme);
        builder.setTitle(R.string.dialog_edit_title)
                .setMessage(R.string.dialog_edit_message)
                .setView(input)
                .setPositiveButton(R.string.dialog_edit_positive_button, (dialogInterface, i) ->
                {
                    // When the positive button is clicked, save the edited task name.
                    String editedText = input.getText().toString();
                    if (!editedText.isEmpty())
                    {
                    saveEditedTaskName(itemView.getContext(), editedText, position);
                    }
                })
                .setNegativeButton(R.string.dialog_edit_negative_button, (dialogInterface, i) -> dialogInterface.cancel());
        // Show the AlertDialog.
        AlertDialog dialog = builder.show();

        input.setOnEditorActionListener((textView, actionId, keyEvent) ->
        {
            // Set the listener for the send button on the EditText.
            if (actionId == EditorInfo.IME_ACTION_SEND)
            {
                // When the send button is clicked, save the edited task name and dismiss the dialog.
                String editedText = input.getText().toString();
                if (!editedText.isEmpty())
                {
                    saveEditedTaskName(itemView.getContext(), editedText, position);
                }
                dialog.dismiss();
                return true;
            }
            return false;
        });
    }

    private void saveEditedTaskName(Context mContext, String editedText)
    {
        // Method to save the edited task name.

        SharedPreferences sharedPrefs = mContext.getSharedPreferences(MainActivity.SHARED_PREFS, 0);
        String categoryId = sharedPrefs.getString(MainActivity.CATEGORY_ID_CHOICE, "");

        FirebaseHelper firebaseHelper = new FirebaseHelper();

        int adapterPosition = getBindingAdapterPosition();
        if (adapterPosition != RecyclerView.NO_POSITION)
        {
            // Problem here!
            Task task = list.get(getBindingAdapterPosition());
            String taskId = task.getTaskId();

            DatabaseReference databaseReference = firebaseHelper.getDatabaseReference();
            databaseReference.child(categoryId).child(DatabaseNodes.TASKS)
                    .child(taskId).child(DatabaseNodes.TASK_NAME).setValue(editedText);

            if (adapter != null)
            {
                adapter.notifyItemChanged(adapterPosition);
            }
        }
        else
        {
            Toast.makeText(mContext, "An error occurred. Please try again.", Toast.LENGTH_SHORT).show();
        }
    }

    // Other code
}

EDIT: I want to add that it seems like the objects where the issue is occurring that the values can’t be renamed because the getBindingAdapterPosition() is returning -1 seem to always be in the same positions, it seems to always be somewhere around the 7th and 8th positioned items in the RecyclerView (indexes 6 & 7). Don’t know if this matters but thought that i’d share it, seems very odd…

EDIT: After further testing, it seems like it’s not only those two positions making trouble, if I have more items it can occur later aswell if the list is longer, but as stated earlier, somewhere usually around the same positions, indexes, 6,7,8.

2

Answers


  1. Chosen as BEST ANSWER

    The issue was solved by passing getBindingAdapterPosition() as an argument in the onLongClick() method call and further to the saveEditedTaskName() method and using that variable received in the parameter instead. I do not exactly know why it works, but it did, perhaps someone else can contribute with an explanation?

    public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
    {
        TextView textView;
        OnItemListener onItemListener;
        ArrayList<Task> list;
        private final RecyclerViewAdapter adapter;
    
        MyViewHolder(@NonNull View itemView, OnItemListener onItemListener, ArrayList<Task> list, RecyclerViewAdapter adapter) {
            super(itemView);
    
            textView = itemView.findViewById(R.id.singleView);
            this.onItemListener = onItemListener;
            this.list = list;
            this.adapter = adapter;
    
            itemView.setOnClickListener(this);
            itemView.setOnLongClickListener(view -> {
                onLongClick(getBindingAdapterPosition());
                return true;
            });
        }
    
        // Other code
    
        private void saveEditedTaskName(Context mContext, String editedText, int position)
        {
            // Method to save the edited task name.
    
            SharedPreferences sharedPrefs = mContext.getSharedPreferences(MainActivity.SHARED_PREFS, 0);
            String categoryId = sharedPrefs.getString(MainActivity.CATEGORY_ID_CHOICE, "");
    
            FirebaseHelper firebaseHelper = new FirebaseHelper();
            if (position != RecyclerView.NO_POSITION)
            {
                Task task = list.get(position);
                String taskId = task.getTaskId();
    
                DatabaseReference databaseReference = firebaseHelper.getDatabaseReference();
                databaseReference.child(categoryId).child(DatabaseNodes.TASKS)
                        .child(taskId).child(DatabaseNodes.TASK_NAME).setValue(editedText);
            }
            else
            {
                Toast.makeText(mContext, "Operation failed, please try again later.", Toast.LENGTH_SHORT).show();
            }
    
            adapter.notifyItemChanged(position);
        }
    
        // Other code
    }
    

  2. The docs say

    Note that if you’ve called notifyDataSetChanged, until the next layout pass, the return value of this method will be NO_POSITION.

    If you want to lazily process your items (where you know the positions don’t change), maybe use getLayoutPosition instead.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search