• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Unreliable/Buggy RecyclerView!

JonasJWW

Newbie
Hey guys,

So for the past weeks I experienced some very weird behavior of my RecyclerView for expanding and collapsing items. I have not figured out a pattern when this behavior occurs. The Problem is that sometimes an Item won't expand even though lytContent.setVisibility(View.VISIBLE); is being called. (Thats what expanding looks like for me currently, I set the Content Layout Visibility to Gone and Visible). This sometimes I need to tapp on the Item twice so expands, sometimes I can tapp on an Item as often as I want and nothing happens and sometimes everything works like it should. I noticed that the more items I have, the more unreliable my RV gets. And as I said, according to my Debugger lytContent.setVisibility(View.VISIBLE); gets called on the right AdapterPosition. Here is a version of my RecyclerView where I have removed almost every features except for expanding/collapsing:

Code:
public class ViewHolder_WorkoutSNR1 extends RecyclerView.Adapter<ViewHolder_WorkoutSNR1.Holder_workoutSNR1> implements ItemTouchHelperAdapter {

    private ItemTouchHelper touchHelper;
    private RecyclerView recyclerView;
    private boolean showingAddExcersise = false;
    private Activity activity;

    private WorkoutSNR workout;
    //private int currentItem;

    private EditText currentTxtRepInput;[MEDIA=youtube]c1kS2gzRZW0[/MEDIA]
    private EditText currentTxtWeightInput;
    private TextView currentTxtSetOverview;
    private TextView currentTxtSetCounter;
    private TextView currentTxtTotalReps;

    public ViewHolder_WorkoutSNR1(Activity activity, WorkoutSNR workout) {
        this.workout = workout;
        this.activity = activity;
    }

    @Override
    public ViewHolder_WorkoutSNR1.Holder_workoutSNR1 onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        final View v1 = inflater.inflate(R.layout.item_exercise_entry_snr, parent, false);
        final Holder_workoutSNR1 holder = new Holder_workoutSNR1(v1);
        holder.lytHeader.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //if (workout.getCurrentEcersise() != holder.getAdapterPosition()) {
                workout.setCurrentEcersise(holder.getAdapterPosition());
                holder.expand();
                notifyDataSetChanged();
                //}
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(Holder_workoutSNR1 holder, int position) {
        final Holder_workoutSNR1 viewHolder = holder;

        if(viewHolder.getAdapterPosition() == workout.getCurrentEcersise()){


        } else {
            viewHolder.collapse();
        }


    }





    @Override
    public int getItemCount() {
        return workout.getExcersises().size();
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        return true;

    }

    @Override
    public void onItemDismiss(int position) { }

    public void setTouchHelper(ItemTouchHelper touchHelper) {
        this.touchHelper = touchHelper;
    }

    public class Holder_workoutSNR1 extends RecyclerView.ViewHolder {

        private Button btnSkipEntry, btnRemove, btnSuperset, btnAddSet, btnNextExercise;
        private ImageButton btnExpand, btnDrag, btnNextSet, btnPreviousSet, btnExpandExerciseOptions, btnTutor;
        private TextView txtExerciseName, txtSetsOverview, txtProgression, txtSetCounter, txtWeightMetric, txtRepMetric, txtTotalReps;
        private EditText txtRepInput, txtWeightInput;
        private ImageView imgTutorResource;
        private LinearLayout btnExerciseNote, lytOptions, lytOptionsContent, lytReachedMax, lytHeader, lytContent;
        private ConstraintLayout lytSetOptions, lytInputWeighted, lytInputReps, lytTutor;
        private Spinner spnProgression;
        private CheckBox cbWeighted;
        private View seperator;

        private boolean expanded;
        private boolean expandedOptions;
        private boolean reachedMaxOptions;

        public Holder_workoutSNR1(View itemView) {
            super(itemView);
            btnExpand = itemView.findViewById(R.id.btnExpand);
            btnDrag = itemView.findViewById(R.id.btnDrag);
            btnNextSet = itemView.findViewById(R.id.btnNextSet);
            btnPreviousSet = itemView.findViewById(R.id.btnPreviousSet);
            btnSkipEntry = itemView.findViewById(R.id.btnSkipEntry);
            btnExpandExerciseOptions = itemView.findViewById(R.id.btnExpandExerciseOptions);
            btnExerciseNote = itemView.findViewById(R.id.btnExcersiseNote);
            txtExerciseName = itemView.findViewById(R.id.txtExerciseName);
            txtSetsOverview = itemView.findViewById(R.id.txtSetsOverview);
            txtProgression = itemView.findViewById(R.id.txtProgression);
            txtSetCounter = itemView.findViewById(R.id.txtSetCounter);
            txtRepInput = itemView.findViewById(R.id.txtRepInput);
            txtWeightInput = itemView.findViewById(R.id.txtWeightInput);
            imgTutorResource = itemView.findViewById(R.id.imgTutorResource);
            lytSetOptions = itemView.findViewById(R.id.lytSetOptions);
            lytOptions = itemView.findViewById(R.id.lytOptions);
            btnSuperset = itemView.findViewById(R.id.btnSuperset);
            btnRemove = itemView.findViewById(R.id.btnRemove);
            spnProgression = itemView.findViewById(R.id.spnProgression);
            cbWeighted = itemView.findViewById(R.id.cbWeighted);
            txtWeightMetric = itemView.findViewById(R.id.txtWeightMetric);
            txtRepMetric = itemView.findViewById(R.id.txtRepMetric);
            lytOptionsContent = itemView.findViewById(R.id.lytOptionsContent);
            btnNextExercise = itemView.findViewById(R.id.btnNextExcersise);
            btnAddSet = itemView.findViewById(R.id.btnAddSet);
            txtTotalReps = itemView.findViewById(R.id.txtTotalReps);
            lytInputReps = itemView.findViewById(R.id.lytInputReps);
            lytInputWeighted = itemView.findViewById(R.id.lytInputWeight);
            lytReachedMax = itemView.findViewById(R.id.lytRechedMax);
            seperator = itemView.findViewById(R.id.sepeator);
            lytTutor = itemView.findViewById(R.id.lytTutor);
            lytHeader = itemView.findViewById(R.id.lytHeader);
            lytContent = itemView.findViewById(R.id.lytContent);
            btnTutor = itemView.findViewById(R.id.btnTutor);
        }

        public void expand() {
         
            btnExpand.setBackgroundResource(R.mipmap.ic_expanded);
        }

        public void collapse() {
            lytContent.setVisibility(View.GONE);
            btnExpand.setBackgroundResource(R.mipmap.ic_action_play_arrow);
        }
    }
}

My RecyclerView items normally have a lot of features so the actual ViewAdapter class is very long. However I feel like the more features it has, the less reliable it is but thats just a felling. I have changed the way I realize expanding/collapsing in may code and have tried it a lot. But the reliability won't get better. Here is a video that shows the weird behavior but with an older code:
. You can see sometimes lytContent.setVisibility(View.GONE); is called but it won't change the visibility. If you want I could do a new video.

I don't think the problem is in my code, I rather think its a bug with RecyclerView. I appreciate any Ideas and Tips.
 
Last edited:
Unless you have a completely reproducible test case which proves beyond all doubt a bug in RecyclerView, I very much doubt the problem lies with that. It will be a problem in your code.
 
Unless you have a completely reproducible test case which proves beyond all doubt a bug in RecyclerView, I very much doubt the problem lies with that. It will be a problem in your code.
Yes probably not but do you have any Idea whats wrong with my code? I
 
Very difficult to answer this, as it needs interactive debugging.
Any chance you could upload your project to Github, and I might be able to lend a hand? No promises though.
 
I think I might have solved this error. Not 100% because I thought that before while it wasn't solved but basically what I have chanced my OnClick of the lytHeader to:

holder.lytHeader.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (holder.getAdapterPosition() != expandedPos) {
if (expandedPos >= 0) {
int prev = expandedPos;
notifyItemChanged(prev);
}

expandedPos = holder.getAdapterPosition();
notifyItemChanged(expandedPos);
}
}
});

So I just notify the Item that was expanded and the item that should be expanded, not every item with
notifyDataSetChanged();. I don't know why this would solve my problem but at the moment it seems like it did...

Thanks LV426 for your answers!
 
Back
Top Bottom