Recyclerview с несколькими таймерами обратного отсчета вызывает мерцание

Я хочу показать, сколько времени осталось в каждой ячейке моего RecyclerView … для этого я использовал таймер обратного отсчета для каждого. В каждой строке я запускаю счетчик и управляю onTick() … все работает так, как ожидалось … У меня есть таймер для каждой строки, и моя ячейка также обновляется, но моя ячейка сейчас мерцает …. и это Сходит с ума, когда я прокручиваю.

Вот мой адаптер …

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

Счетчик кода, как показано ниже ….

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

Solutions Collecting From Web of "Recyclerview с несколькими таймерами обратного отсчета вызывает мерцание"

Вам нужно добавить таймер обратного отсчета в свой метод onCreateViewHolder RecyclerView, потому что onCreateViewHolder будет вызываться только один раз.

OnBindViewHolder будет вызываться каждый раз, когда пользователь прокручивает вверх или вниз

Пожалуйста, проверьте код ниже.

 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. * * */ } } 

}

Thanx Hammad Tariq Sahi, я использовал вашу логику и решил свою проблему таким образом …. я также ссылался на эту ссылку

В моем адаптере

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

Внутренний конструктор моего адаптера

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

И добавил этот метод для вычисления времени

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

Добавили два метода в класс моего зрителя

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

И, наконец, внутри onBindViewHolder

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

Работает отлично …. спасибо всем