Countdown timer in Flcikers in RecyclerView

46 Views Asked by At

I have two tab in my fragment.In my recyclerview there are two viewtypes, those two viewtype populates on depending of press in chips.On create view it works fine. But when I come back from the second viewtype the my countDown timer in the first viewtype flickers a bit. It shows a one number then changes to another.

long timeUntilStart = startDate.getTime() - currentTime.getTime();
                long timeUntilEnd = endDate.getTime() - currentTime.getTime();
                if (timeUntilStart > 0) {
                    CountDownTimer timer = new CountDownTimer(timeUntilStart, 1000) {
                        public void onTick(long millisUntilFinished) {
                            // Update the countdown timer text
                            long seconds = (millisUntilFinished / 1000) % 60;
                            long minutes = (millisUntilFinished / (1000 * 60)) % 60;
                            long hours = (millisUntilFinished / (1000 * 60 * 60));
                            ((ExamListV2ActiveItemViewHolder) holder).binding.tvRemainingTime.setText(String.format("%02d Hour: %02d min :%02d sec", hours, minutes, seconds));
                        }

                        public void onFinish() {
                            ((ExamListV2ActiveItemViewHolder) holder).binding.btnJoin.setVisibility(View.VISIBLE);
                            ((ExamListV2ActiveItemViewHolder) holder).binding.tvStarts.setText(context.getResources().getString(R.string.exam_starts_in));
                            ((ExamListV2ActiveItemViewHolder) holder).binding.btnJoin.setVisibility(View.VISIBLE);
                            CountDownTimer timer = new CountDownTimer(timeUntilEnd, 1000) {
                                public void onTick(long millisUntilFinished) {
                                    // Update the countdown timer text
                                    long seconds = (millisUntilFinished / 1000) % 60;
                                    long minutes = (millisUntilFinished / (1000 * 60)) % 60;
                                    long hours = (millisUntilFinished / (1000 * 60 * 60));
                                    ((ExamListV2ActiveItemViewHolder) holder).binding.tvRemainingTime.setText(String.format("%02d Hour %02d Min %02d Sec", hours, minutes, seconds));
                                }

                                public void onFinish() {
                                    ((ExamListV2ActiveItemViewHolder) holder).binding.tvRemainingTime.setText(context.getResources().getString(R.string.exam_ended));
                                }
                            };
                            timer.start();
                        }
                    };
                    timer.start();

here is my code. can anyone point out what i can do to avoid this

1

There are 1 best solutions below

0
Dimi On BEST ANSWER

You should probably move the CountDownTimer logic inside the holder itself and make sure to react on onViewRecycled otherwise you creating one CountDownTimer for 2 holders and i guess they interfere each other

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    super.onViewRecycled(holder);
    ((ExamListV2ActiveItemViewHolder) holder).startTimer(startDate, endDate);
}

@Override
public void onViewRecycled(@NonNull ViewHolder holder) {
    super.onViewRecycled(holder);
    ((ExamListV2ActiveItemViewHolder) holder).resetTimer();
}

Your holder would be like:

class ExamListV2ActiveItemViewHolder extends RecyclerView.ViewHolder {
    CountDownTimer timer;
    
    public ExamListV2ActiveItemViewHolder(@NonNull View itemView) {
        super(itemView);
    }

    public void startTimer(final Date startDate, final Date endDate) {
        final Date currentTime = new Date();
        final long timeUntilStart = startDate.getTime() - currentTime.getTime();
        final long timeUntilEnd = endDate.getTime() - currentTime.getTime();
        if (timeUntilStart > 0) {
            timer = new CountDownTimer(timeUntilStart, 1000) {
                public void onTick(long millisUntilFinished) {
                    setCountDownTime(millisUntilFinished);
                }

                public void onFinish() {
                    binding.btnJoin.setVisibility(View.VISIBLE);
                    binding.tvStarts.setText(itemView.getContext().getResources().getString(R.string.exam_starts_in));
                    binding.btnJoin.setVisibility(View.VISIBLE);
                    timer = new CountDownTimer(timeUntilEnd, 1000) {
                        public void onTick(long millisUntilFinished) {
                            setCountDownTime(millisUntilFinished);
                        }

                        public void onFinish() {
                            binding.tvRemainingTime.setText(itemView.getContext().getResources().getString(R.string.exam_ended));
                        }
                    };
                    timer.start();
                }
            };
            timer.start();
        }
    }

    public void resetTimer() {
        if (timer != null) timer.cancel();
    }

    private void setCountDownTime(long time) {
        long seconds = (time / 1000) % 60;
        long minutes = (time / (1000 * 60)) % 60;
        long hours = (time / (1000 * 60 * 60));
        binding.tvRemainingTime.setText(String.format("%02d Hour: %02d min :%02d sec", hours, minutes, seconds));
    }
}