Search code examples
javaandroidandroid-recyclerviewcountdowntimer

Countdown timer in Flcikers in RecyclerView


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


Solution

  • 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));
        }
    }