Multiple Count Down Timers in Recyclerview Flickering When Scrolled

Multiple count down timers in RecyclerView flickering when scrolled

This problem is simple.

RecyclerView reuses the holders, calling bind each time to update the data in them.

Since you create a CountDownTimer each time any data is bound, you will end up with multiple timers updating the same ViewHolder.

The best thing here would be to move the CountDownTimer in the FeedViewHolder as a reference, cancel it before binding the data (if started) and rescheduling to the desired duration.

public void onBindViewHolder(final FeedViewHolder holder, final int position) {
...
if (holder.timer != null) {
holder.timer.cancel();
}
holder.timer = new CountDownTimer(expiryTime, 500) {
...
}.start();
}

public static class FeedViewHolder extends RecyclerView.ViewHolder {
...
CountDownTimer timer;

public FeedViewHolder(View itemView) {
...
}
}

This way you will cancel any current timer instance for that ViewHolder prior to starting another timer.

Recyclerview with multiple countdown timers causes flickering

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

Android Count Down Timer in RecyclerView flickers between two values

check this Multiple count down timers in RecyclerView flickering when scrolled

On onBindViewHolder check if timer is already initialized or not. If initialized then cancel it first and then start it.

How to fix timer when scrolling on RecyclerView on Android?

When you want use Timer into your adapter, Shouldn't use this in onBindViewHolder.

Because onBindViewHolder call every when you scrolling on items

You should use Timer into constructor of your Adapter, and every second notifyDataSetChanged your adapter.

Don't worry, this is way not bad structure and not memory leak. you can check this in profile tab!

class AuctionsTodayAdapter(val context: Context, val model: MutableList<Today>) :
RecyclerView.Adapter<AuctionsTodayAdapter.MyHolder>() {

private var newData: Long = 0

init {
for (items in model) {
items.end.let {
newData = items.end.toLong()
}
}
//set the timer which will refresh the data every 1 second.
object : CountDownTimer(newData, 1000) {
override fun onFinish() {
notifyDataSetChanged()
}

override fun onTick(p0: Long) {
var i = 0
val dataLength = model.size
while (i < dataLength) {
val item = model[i]
item.end -= 1000
i++
}
notifyDataSetChanged()
}
}.start()
}

override fun onBindViewHolder(holder: MyHolder, position: Int) {
var modelUse = model[position]
//Img
modelUse.image.let {
Glide.with(context)
.load(Constants.MAIN_BASE_URL + it)
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.RESOURCE))
.into(holder.rowMAIN_img)
}
//Timer
modelUse.end.let {
if (modelUse.calculateEnd > 0) {
holder.rowMAIN_timer.text = getDurationBreakdown(modelUse.end.toLong())
} else {
holder.rowMain_timer.text = "Finished"
}
}
}

private fun millToMins(milliSec: Long): String {
var seconds = (milliSec / 1000).toInt()
val hours = seconds / (60 * 60)
val tempMint = seconds - hours * 60 * 60
val minutes = tempMint / 60
seconds = tempMint - minutes * 60

return String.format("%02d", hours) + ":" + String.format(
"%02d",
minutes
) + ":" + String.format("%02d", seconds)
}
}

I hope i can help you.

Countdown timer in recyclerview not working properly

The issue is that on every onBindViewHolder call you are creating a new CountDownTimer and updating that ViewHolder. So after a couple of scrolls, multiple CountDownTimer will try to update the same ViewHolder.

Create only one CountDownTimer per ViewHolder. To do that, cancel the CountDownTimer by calling the .cancel(); on it before setting a new CountDownTimer on the ViewHolder.

In order to get access to the CountDownTimer already set on a ViewHolder, create it on onCreateViewHolder and put it inside MyViewHolder as a field.

Have a public method on MyViewHolder called say update which does all the procedure you have written in onBindViewHolder and simple call update in onBindViewHolder of the Adapter. (cleaner code too :) )

ListView with Coundown timer. Timer flickers when scrolling the listview

UPDATE

I updated my answer here have a look: (it's uses cardview with recyclerview but the same principle can be applied also for listview)
How to change text based on time and date?

You have to take care when you create the countdowntimer instance and when you cancel it. If you don't cancel the timer it will update the wrong views.



Related Topics



Leave a reply



Submit