RecyclerView item removal behaves aberrantly

admin

Administrator
Staff member
I am using this <a href="https://therubberduckdev.wordpress....yclerview-drag-and-drop-and-swipe-to-dismiss/" rel="nofollow noreferrer">tutorial</a> to build an itemTouchListener for my RecyclerView. The recyclerview is filled with more items than the screen fits (more than 10), so recycling gets into action. The itemtouchHelper handles both up-down and left-right movement. After 2 days of struggle (had setStableIds to true which caused flickering of the viewholder views when the were moved up-down), I finally got a better behaviour. My code of the crucial features:

Code:
  @Override
    public int getItemCount() {
        return questionlist.size();
    }

    @Override
    public void onViewMoved(int oldPosition, int newPosition) {
        targetqueobj = questionlist.get(oldPosition);

        this.fromPosition = oldPosition;
        this.toPosition = newPosition;
        questionlist.remove(targetqueobj);
        questionlist.add(newPosition, targetqueobj);

        //    targetqueobj.setinturn(toPosition+1);
    }



    @Override
    public void onViewSwiped(final RecyclerView.ViewHolder thisviewholder,final int position, int direction) {
        targetqueobj = questionlist.get(position);
        if (direction == ItemTouchHelper.LEFT){
            // saveqset();
            Intent intent = new Intent(context, QuestionEditActivity.class);
            intent.putExtra("com.logictop.mqapp.QuestionObjParcelable",targetqueobj);
            context.startActivity(intent);
        }
        if (direction == ItemTouchHelper.RIGHT) {
            // DIALOG
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setMessage(R.string.remove_question);
            builder.setNegativeButton(R.string.No, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface arg0, int arg1) {
             //       thisviewholder.itemView.setAlpha(1);
                    notifyDataSetChanged();
                }
            });

            builder.setPositiveButton(R.string.Yes, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface arg0, int arg1) {
                    questionlist.remove(position);
                    notifyItemRemoved(position);
                    notifyItemRangeChanged(position, getItemCount()-position);
                }
            });
            Dialog dialog = builder.create();
            dialog.setCancelable(false);
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();

        }
    }
    if (direction == ItemTouchHelper.RIGHT) {
        // DIALOG
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage(R.string.remove_question);
        builder.setNegativeButton(R.string.No, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface arg0, int arg1) {
                thisviewholder.itemView.setAlpha(1);
                notifyDataSetChanged();
            }
        });

        builder.setPositiveButton(R.string.Yes, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface arg0, int arg1) {
                questionlist.remove(position);
                notifyItemRemoved(position);
                notifyItemRangeChanged(position, getItemCount()-position);
            }
        });
        Dialog dialog = builder.create();
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);
        dialog.show();

    }
}

The problem is this. Though the recyclerview runs smoothly with the items very nicely changing positions, when an item is swiped away, sometimes another item looks also removed when the recyclerview is scrolled down (so it seems that the other item that gets removed fills the same "screen" position in the recyclerview after it is scrolled). It doesn't happen every time and it mostly happens when a view in some specific positions are swiped away. That "gap" can be mended if I move a neighbor view up or down.

<a href=" " rel="nofollow noreferrer"><img src=" " alt="sorry, you have to wait for a bit to see the thing happening after I remove a view for the second time and scroll down"></a>

I have tried every solution I found in here (notifyDataChanged, notifyItemRangeChanged (with every parameter compination). But nothing could get me a stable behaviour. AFter a lot of stackoverflow searching I decided to follow the advice of
Code:
holder.setIsRecyclable(false)
even though I didn't want to do that (as it eliminates the point of having a recyclerview after all). But in that case, other problems appear. You'll see below that when most of the views are swiped away, they lower ones won't leave the screen, even though they apparently have "left the adapter" (cannot swipe them away). And in the end, the last views stay stuck.

<a href=" " rel="nofollow noreferrer"><img src=" " alt="you have to wait a bit here as well, in the end you&#39;ll see the stuck views"></a>

I have tested both ways on a completely new project with nothing external coming into the way. I have tried putting
Code:
notifyDataChanged()
in an overriden function of clearView. Nothing seems to provide a rock solid stable recyclerview that won't get at some point a gap in itself.

The question now: is there a way to make a recyclerview with working recycling behave like it is supposed to behave or should I accept that situation?
Thank you very much for your attention!

<strong>UPDATE 1----------------------------</strong>
As I was told there could be an issue with this
Code:
thisviewholder.itemView.setAlpha(1);
I commented it out along with the corresponding overriden onChildDraw (the whole of it) that is used to fade the view out when it is swiped out. So now nothing gets invisible. Still the problem persists.

<strong>UPDATE 2----------------------------</strong>
I have enforced stableIds (had already done that once and it didn't work)

Code:
@Override
public long getItemId(int position){
    return questionlist.get(position).getquestionid();
}

and the adapter contructor

Code:
public QSetEditAdapter(ArrayList&lt;QuestionObj_prcl&gt; questionlist, Context context) {
        this.context = context;
        this.questionlist = questionlist;
        setHasStableIds(true);
    }

Still the problem persists.

<strong>UPDATE 3----------------------------</strong>
I ended up using a <a href="https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf" rel="nofollow noreferrer">different tutorial</a> and now everything works as expected. Thanks a lot!