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
How to Add a Gesture Detector to a View in Android
Android Xml VS Java Layouts Performance
How to Upload File Using Volley Library in Android
Display All Unicode Chars in Textview
Fragment-Fragment Communication in Android
Resource Linking Fails on Lstar
Difference Between Finish() and System.Exit(0)
Installation Error: Install_Failed_Older_Sdk
How to Completely Kill/Remove/Delete/Stop an Asynctask
Connect to Wifi in Android Q Programmatically
Limit Scrolling and Zooming Google Maps Android API V2
How to Hide System Bar on Android Ics
How to Add Shadow to the Fab Provided with the Android Support Design Library
Notifications Fail to Display in Android Oreo (API 26)
Android Viewpager Setcurrentitem Not Working After Onresume