1

I have the following recyclerview:

enter image description here

When I press Start button a CountDownTimer starts to countdown,but the problem is,that if I start the countdown on question example 1 (or any other question element) the countdown starts, but if I scroll down to the bottom of the recyclerview the timer resets.

The second problem is, that when I switch from this fragment to another(for example:going back to previous fragment with backpress) the timer resets.

I don't know, how to fix this problems, please help me.

My adapter for the recyclerview is the following:


import android.content.Context;
import android.os.CountDownTimer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.text.MessageFormat;
import java.util.ArrayList;

public class QuestionsAdapter extends RecyclerView.Adapter<QuestionsAdapter.QuestionsViewHolder>
{
    Context context;
    ArrayList<Question> questions;

    public static class QuestionsViewHolder extends RecyclerView.ViewHolder
    {
        public TextView questionname;
        public TextView status;
        public TextView timereamining;
        public Button start;

        public QuestionsViewHolder(View v)
        {
            super(v);

            questionname=v.findViewById(R.id.questiontext);
            status=v.findViewById(R.id.statusstr);
            timereamining=v.findViewById(R.id.time);
            start=v.findViewById(R.id.startbutton);
        }
    }

    public QuestionsAdapter(Context context,ArrayList<Question> dataset)
    {
        this.context=context;
        this.questions=dataset;
    }

    @NonNull
    @Override
    public  QuestionsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
    {
        View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.listofquestions,parent,false);

        return new QuestionsViewHolder(v);
    }

    @Override
    public void onBindViewHolder(@NonNull final QuestionsViewHolder holder, final int position)
    {
        holder.questionname.setText(questions.get(position).getQuestionname());
        holder.status.setText(questions.get(position).getStatus());
        holder.timereamining.setText(String.valueOf(questions.get(position).getTimelimit())+":00");

        holder.start.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                new CountDownTimer(questions.get(position).getTimelimit()*60000, 1000)
                {
                    public void onTick(long millisUntilFinished)
                    {
                        long minutes=millisUntilFinished/60000;
                        long seconds=millisUntilFinished%60000/1000;

                        String timeleft;

                        timeleft=""+minutes;
                        timeleft+=":";
                        if(seconds<10)
                        {
                            timeleft+="0";
                        }

                        timeleft+=seconds;
                        holder.timereamining.setText(timeleft);

                    }

                    public void onFinish()
                    {
                        holder.timereamining.setText("done!");
                    }

                }.start();
            }
        });
    }

    @Override
    public int getItemCount()
    {
        return questions.size();
    }
}
lambozsolty
  • 81
  • 10
  • So, a timer for each question can be started only once, can't it? Even if a user leaves your `Fragment` and then comes back? – Anatolii Nov 20 '19 at 21:19

2 Answers2

0

The problem you are encountering is due to the inherent nature of RecyclerView. This is a good resource that explains what is happening: Understanding RecyclerView.

When the RecyclerView recycles your item row, you will lose any state that you are holding in that row. A few ideas that might help you accomplish what you are after would be starting each counter uniquely outside of your item row and maintaining a relationship inside your adapter, so when you scroll back to that item position, the row can reconnect to its counter. You could also possibly use a list view, as it will not (always) recycle your rows, but after thinking about this I wouldn't recommend it. List View Recycling

Richard Dapice
  • 838
  • 5
  • 10
  • Thank you,I will try to use list view. – lambozsolty Nov 20 '19 at 22:27
  • I would do that only as your last resort, the list view will still be prone to recycling when your data gets too large. I would first try implementing another pattern than putting your timers in each row. – Richard Dapice Nov 20 '19 at 22:33
0

When a item scrolled out of screen, recyclerview will recycle this item.

That means, onBindViewHolder for same positon will into several times, and a particular viewHolder will present for different data depends depends scroll state.

Consider onTick method should change data, and call adapter's notifyItemChagne method rather than change viewHolder directly.

more detail

wuyi
  • 227
  • 1
  • 17