Home » Android » android – Recyclerview with multiple countdown timers causes flickering

android – Recyclerview with multiple countdown timers causes flickering

Posted by: admin June 16, 2020 Leave a comment

Questions:

I want to show how much time is left inside each cell of my RecyclerView…for that I have used a countdown timer for each. In each row I start a counter and manage onTick()…all works as expected…I’ve got a timer tick for each row and my cell is also updating but my cell is flickering now….and it goes crazy when I scroll.

Here is my adapter…

if (product.getProductType().equalsIgnoreCase("Auction Product")) {
                isAuction=true;
                viewHolder.img_product_type.setImageResource(R.drawable.bid);
                viewHolder.txt_timeleft.setVisibility(View.VISIBLE);
               start_countDown(product.getStart(),product.getStop(),viewHolder.txt_timeleft);
            }

counter code is as below….

private void start_countDown(String start, String stop, final TextView txt_timeleft) {
        try {
            //Log.e("hetal",start+"....."+stop);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            Calendar start_date = Calendar.getInstance();
            start_date.setTime(format.parse(start));

            Calendar end_date = Calendar.getInstance();
            end_date.setTime(format.parse(stop));

            final Calendar today = Calendar.getInstance();
            CountDownTimer timer;

            txt_timeleft.setTextColor(Color.DKGRAY);
            if(today.before(start_date)){
                txt_timeleft.setTextColor(context.getResources().getColor(R.color.red));
                txt_timeleft.setText(context.getString(R.string.auction_not_start));
                Animation anim = new AlphaAnimation(0.0f, 1.0f);
                anim.setDuration(1000); //You can manage the time of the blink with this parameter
                anim.setStartOffset(20);
                anim.setRepeatMode(Animation.REVERSE);
                anim.setRepeatCount(Animation.INFINITE);
                txt_timeleft.startAnimation(anim);
                return;
            }
            if (!today.before(end_date)) {

                txt_timeleft.setTextColor(context.getResources().getColor(R.color.red));
                txt_timeleft.setText(context.getString(R.string.time_out));
                        Animation anim = new AlphaAnimation(0.0f, 1.0f);
                        anim.setDuration(1000); //You can manage the time of the blink with this parameter
                        anim.setStartOffset(20);
                        anim.setRepeatMode(Animation.REVERSE);
                        anim.setRepeatCount(Animation.INFINITE);
                txt_timeleft.startAnimation(anim);
                return;
            }

            timer = new CountDownTimer(end_date.getTimeInMillis(), 1000) {
                @Override
                public void onTick(long millisUntilFinished) {

                    Calendar calendar = Calendar.getInstance();
                    calendar.setTimeInMillis(millisUntilFinished);

                    long diff = calendar.getTimeInMillis() - today.getTimeInMillis();

                    long seconds = diff / 1000 % 60;
                    long minutes = diff / (60 * 1000) % 60;
                    long hours = diff / (60 * 60 * 1000) % 24;
                    //long days = (int) diff / (24 * 60 * 60 * 1000);
                    long days = TimeUnit.MILLISECONDS.toDays(diff);


                    String left = "";
                    if (days > 0)
                        left += days + " " + context.getString(R.string.txt_day) + " ,";
                    if (hours > 0)
                        left += hours + " " + context.getString(R.string.txt_hour) + " ,";
                    if (minutes > 0)
                        left += minutes + " " + context.getString(R.string.txt_minute) + " ,";

                    left += seconds + " " + context.getString(R.string.txt_second);

                    final String finalLeft = left;


                            if (finalLeft.equals("0") || finalLeft.contains("-")) {
                                txt_timeleft.setText(context.getString(R.string.time_out));
                                txt_timeleft.setTextColor(context.getResources().getColor(R.color.red));
                                Animation anim = new AlphaAnimation(0.0f, 1.0f);
                                anim.setDuration(1000); //You can manage the time of the blink with this parameter
                                anim.setStartOffset(20);
                                anim.setRepeatMode(Animation.REVERSE);
                                anim.setRepeatCount(Animation.INFINITE);
                                txt_timeleft.startAnimation(anim);
                            } else
                                txt_timeleft.setText(finalLeft);
                }

                @Override
                public void onFinish() {

                }
            };
            timer.start();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
How to&Answers:

thanx Hammad Tariq Sahi i have used your logic and solve my problem in this way….i have also refereed this link

in my adapter

ArrayList<ViewHolder> viewHoldersList;
    private Handler handler = new Handler();
    private Runnable updateRemainingTimeRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (viewHoldersList) {
                for (ViewHolder holder : viewHoldersList) {
                    holder.updateTimeRemaining();
                }
            }
        }
    };

inside constructor of my adapter

viewHoldersList = new ArrayList<>();
startUpdateTimer();

and added this method to calculate time

private void startUpdateTimer() {
        Timer tmr = new Timer();
        tmr.schedule(new TimerTask() {
            @Override
            public void run() {
                handler.post(updateRemainingTimeRunnable);
            }
        }, 1000, 1000);
    }

added two methods to my viewholder class

public void setData(Product product){
            this.product = product;
        }
        public void updateTimeRemaining() {
            if(product.getProductType().equalsIgnoreCase("Auction Product")) {
                Log.e("hetal",product.getProductType());
                try {
                    String start = product.getStart();
                    String stop = product.getStop();

                    //txt_timeleft.setText("");
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                    Calendar start_date = Calendar.getInstance();
                    start_date.setTime(format.parse(start));

                    Calendar end_date = Calendar.getInstance();
                    end_date.setTime(format.parse(stop));

                    final Calendar today = Calendar.getInstance();
                    CountDownTimer timer;

                    long timeDiff = end_date.getTimeInMillis() - today.getTimeInMillis();
                    if (timeDiff > 0) {
                        long seconds = timeDiff / 1000 % 60;
                        long minutes = timeDiff / (60 * 1000) % 60;
                        long hours = timeDiff / (60 * 60 * 1000) % 24;
                        //long days = (int) diff / (24 * 60 * 60 * 1000);
                        long days = TimeUnit.MILLISECONDS.toDays(timeDiff);


                        String left = "";
                        if (days > 0)
                            left += days + " " + context.getString(R.string.txt_day) + " ,";
                        if (hours > 0)
                            left += hours + " " + context.getString(R.string.txt_hour) + " ,";
                        if (minutes > 0)
                            left += minutes + " " + context.getString(R.string.txt_minute) + " ,";

                        left += seconds + " " + context.getString(R.string.txt_second);

                        final String finalLeft = left;
                        txt_timeleft.setText(finalLeft);
                    } else {
                        txt_timeleft.setText("Time Out !!");
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }

and finally inside onBindViewHolder

synchronized (viewHoldersList) {
                viewHolder.setData(product);
                if(viewHoldersList.size()< (list.size()-2)) viewHoldersList.add(viewHolder);
            }

works perfect….thanx all

Answer:

You need to add count down timer in your onCreateViewHolder method of RecyclerView because onCreateViewHolder will be called only once.

onBindViewHolder will be called every time user scroll up or down

please check below code.

public class UsageDetailsAdapter extends RecyclerView.Adapter<UsageDetailsAdapter.ViewHolder> {

Context mContext;
int position;
DecoView decoView;

public UsageDetailsAdapter(Context context) {

    this.mContext = context;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_adapter_usage_details, parent, false);
    decoView = (DecoView) view.findViewById(R.id.dynamicArcView);


    Toast.makeText(mContext,""+ position, Toast.LENGTH_SHORT).show();


    position++;
    return new ViewHolder(view);


}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    /*
    * onBindViewHolder will be called every time user scroll up or down
    *
    * */


}

@Override
public int getItemCount() {
    return 10;
}

public class ViewHolder extends RecyclerView.ViewHolder {

    public ViewHolder(View itemView) {
        super(itemView);
        decoView = (DecoView) itemView.findViewById(R.id.dynamicArcView);
        decoView.setBackgroundColor(mContext.getResources().getColor(R.color.textColorPrimary));
        /*
        * View holder will be called once, but if user scroll before completing arc view
        * animation will not be completed.
        *
        * */
    }
}

}