Android studio, recycle view

Viewed 132

I have some error in android studio. When i try to add symbol ('*') to special item, it also add the symbol to the item that placed in +14 from the first. I will glad if someone have solution for this problem. For more information you can check this link, where i describe the problem. https://youtu.be/CJFkt-Cck1A

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {

    private static final String TAG = "RecyclerViewAdapter";
    private Context context;
    private List<WorkDayItem> workDayItemList;

    //Complete
    public RecyclerViewAdapter(Context context, List<WorkDayItem> workDayItemList) {
        this.context = context;
        this.workDayItemList = workDayItemList;
    }

    //Complete
    //Here we create view- itemWorkday and inflate it by layout- item_one_work_day
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View itemWorkDay = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_one_work_day, parent, false);
        MyViewHolder myViewHolder = new MyViewHolder(itemWorkDay);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        Log.d(TAG, "onBindViewHolder: called." + (position + 1) + "\n" + workDayItemList.get(position).toString());

        final WorkDayItem workDayItem = workDayItemList.get(position);
        String dateStart = (String) DateFormat.format("dd.MM", workDayItem.getDateStart());
        String timeStart = (String) DateFormat.format("HH:mm", workDayItem.getDateStart());
        String timeEnd = (String) DateFormat.format("HH:mm", workDayItem.getDateEnd());

        //Convert data from firebase String format to int hours and minutes format.
        Double convertingDataFromFirebase;
        try {
            convertingDataFromFirebase = Double.parseDouble(new DecimalFormat("##.##").format(workDayItem.getCount_hours()));
        } catch (NumberFormatException e) {
            convertingDataFromFirebase = 0.0;
        }

        int hours = convertingDataFromFirebase.intValue();

        convertingDataFromFirebase = (convertingDataFromFirebase - convertingDataFromFirebase.intValue()) * 60;
        int minutes = convertingDataFromFirebase.intValue();

        //Check if current item have description
        if (workDayItemList.get(position).getDesc().length() > 2) {
            Log.i(TAG, "TESTER: desc dote added");
            holder.doteOfDesc.setVisibility(View.VISIBLE);
        }


        holder.dayPosition.setText((position + 1) + "");
        holder.dateStart.setText(dateStart);
        holder.timeStart.setText(timeStart);
        holder.timeEnd.setText(timeEnd);
        holder.countOfHours.setText(hours + ":" + minutes);


        //On click on current hold open alert dialog with some functions
        holder.parentLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                initializeAlertDialogForItem(workDayItem, holder);
            }
        });

    }


    //initialize data about current work day and have button for changing information
    private void initializeAlertDialogForItem(final WorkDayItem workDayItem, final MyViewHolder holder) {

        //Initialize alert dialog
        final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
        View itemWork = LayoutInflater.from(context)
                .inflate(R.layout.ad_item_desc, null, false);
        alertDialog.setView(itemWork);
        alertDialog.show();


        //initialize alert dialog buttons and views
        final ImageButton change = alertDialog.findViewById(R.id.itemAD_Edit);
        final ImageButton delete = alertDialog.findViewById(R.id.itemAD_Delete);

        TextView description = alertDialog.findViewById(R.id.itemADDescription);
        TextView date = alertDialog.findViewById(R.id.itemADDate);
        TextView from = alertDialog.findViewById(R.id.itemADFrom);
        TextView to = alertDialog.findViewById(R.id.itemADTO);

        String timeStart = (String) (DateFormat.format("HH:mm", workDayItem.getDateStart()));
        String timeEnd = (String) (DateFormat.format("HH:mm", workDayItem.getDateEnd()));
        String dateStart = (String) (DateFormat.format("dd.MM.yyyy", workDayItem.getDateStart()));


        date.setText(dateStart);
        from.setText(timeStart);
        to.setText(timeEnd);
        description.setText(workDayItem.getDesc());
        //Change button
        change.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.M)
            @Override
            public void onClick(View v) {
                AlertDialogReport userReport = new AlertDialogReport(context, "replace-remove", workDayItem);
                userReport.initializeAlertDialog();
                alertDialog.dismiss();
            }
        });

        delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Delete data from firebase

                Login.fc.databaseReference.addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                        for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                            String itemTime = "" + workDayItem.getDateStart().getTime();
                            String firebaseTime = "" + snapshot.child("dateStart").child("time").getValue();
                            if (itemTime.equals(firebaseTime)) {
                                Login.fc.databaseReference.child(snapshot.getKey()).removeValue();
                            }
                        }
                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError databaseError) {
                    }
                });
                //Delete data from SqLiteDatabase
                MySQLDataBase dataBase = new MySQLDataBase(context);
                dataBase.deleteItem(workDayItem);

                //Finish with alert dialog and notify user
                alertDialog.dismiss();
                Toast.makeText(context, R.string.item_deleted, Toast.LENGTH_SHORT).show();
                holder.parentLayout.removeAllViews();
            }
        });

    }


    //Complete
    @Override
    public int getItemCount() {
        return workDayItemList.size();
    }


    //Complete
    //Here we catch our view and getting reference between view and our objects
    public class MyViewHolder extends RecyclerView.ViewHolder {
        private LinearLayout parentLayout;
        private TextView doteOfDesc, dayPosition, dateStart, timeStart, timeEnd, countOfHours;

        public MyViewHolder(View view) {
            super(view);
            doteOfDesc = view.findViewById(R.id.itemDote);
            dayPosition = view.findViewById(R.id.itemDayPosition);
            dateStart = view.findViewById(R.id.itemDateStart);
            timeStart = view.findViewById(R.id.itemStartHour);
            timeEnd = view.findViewById(R.id.itemEndHour);
            countOfHours = view.findViewById(R.id.itemCountOfHours);
            parentLayout = view.findViewById(R.id.itemWorkDay);
        }
    }

}
1 Answers

Try adding this:

    //Check if current item have description
    if (workDayItemList.get(position).getDesc().length() > 2) {
                Log.i(TAG, "TESTER: desc dote added");
                holder.doteOfDesc.setVisibility(View.VISIBLE);
            }
    else if( workDayItemList.get(position).getDesc().length() < 2 
             && holder.doteOfDesc.getVisibility()== View.VISIBLE ){
     holder.doteOfDesc.setVisibility(View.GONE);
}

The reason why this is happening is that RecyclerView creates as many ViewHolders as its needed to cover a whole screen plus few extra ( 12 in your case) then reuses them via rebinding values to views. And you set doteOfDescto View.VISIBLE in 2. ViewHolder, but never set it back to View.GONE, thats why every time that ViewHolder is reused it will have doteOfDesc visible.

The Prettier version:

  Boolean hasDescription = workDayItemList.get(position).getDesc().length() > 2;
  holder.doteOfDesc.setVisibility( hasDescription ? View.VISIBLE : View.GONE);
Related