简体   繁体   中英

How to use multiple countDownTimer into recyclerView on Android

In my application i want use multiple CountDownerTimer for show offer times into RecyclerView .
For write this application i used Kotlin language.
I write below codes, but when scrolling on recyclerView 's items start again this timer !

My mean is, timer started from 4:19 sec, when scrolling on items and after 10sec show me 4:19 again instead of 4:09 !

Activity codes:

class MainActivity : AppCompatActivity() {

    private lateinit var apisList: ApisList
    private lateinit var retrofit: Retrofit
    private lateinit var todayAdapter: AuctionsTodayAdapter
    private val todayModel: MutableList<Today> = mutableListOf()
    private lateinit var layoutManager: RecyclerView.LayoutManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //Initialize
        retrofit = ApiClient.instance
        apisList = retrofit.create(ApisList::class.java)
        todayAdapter = AuctionsTodayAdapter(themedContext, todayModel)
        layoutManager = LinearLayoutManager(themedContext)
        //RecyclerView
        main_list.setHasFixedSize(true)
        main_list.layoutManager = layoutManager
        main_list.adapter = todayAdapter

        if (isNetworkAvailable()) getData(1, 10)
    }

    private fun getData(page: Int, limit: Int) {
        main_loader.visibility = View.VISIBLE
        val call = apisList.getAuctionsToday(page, limit)
        call.let {
            it.enqueue(object : Callback<AuctionsTodayResponse> {
                override fun onFailure(call: Call<AuctionsTodayResponse>, t: Throwable) {
                    main_loader.visibility = View.GONE
                    Log.e("auctionsTodayList", t.message)
                }

                override fun onResponse(call: Call<AuctionsTodayResponse>, response: Response<AuctionsTodayResponse>) {
                    if (response.isSuccessful) {
                        response.body()?.let { itBody ->
                            main_loader.visibility = View.GONE
                            if (itBody.toString().isNotEmpty()) {
                                todayModel.clear()
                                todayModel.addAll(itBody.res.today)
                                todayAdapter.notifyDataSetChanged()
                            }
                        }
                    }
                }
            })
        }
    }
}

Adapter codes:

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

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.row_main_list, parent, false)
        val holder = MyHolder(view)

        //holder.setIsRecyclable(false)

        return holder
    }

    override fun getItemCount(): Int {
        return model.size
    }

    override fun onBindViewHolder(holder: MyHolder, position: Int) {
        val modelUse = model[position]
        holder.setData(modelUse)



        if (holder.newCountDownTimer != null) {
            holder.newCountDownTimer!!.cancel()
        }
        var timer = modelUse.calculateEnd

        timer = timer * 1000

        holder.newCountDownTimer = object : CountDownTimer(timer, 1000) {
            override fun onTick(millisUntilFinished: Long) {
                var seconds = (millisUntilFinished / 1000).toInt()
                val hours = seconds / (60 * 60)
                val tempMint = seconds - hours * 60 * 60
                val minutes = tempMint / 60
                seconds = tempMint - minutes * 60
                holder.rowMain_timer.rowMain_timer.text =
                    String.format("%02d", hours) + ":" + String.format(
                        "%02d",
                        minutes
                    ) + ":" + String.format("%02d", seconds)
            }

            override fun onFinish() {
                holder.rowMain_timer.text = "00:00:00"
            }
        }.start()

    }

    inner class MyHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        var newCountDownTimer: CountDownTimer? = null

        lateinit var rowMain_timer: TextView

        init {
            rowMain_timer = itemView.findViewById(R.id.rowMain_timer)
        }

        fun setData(model: Today) {
            model.image.let {
                Glide.with(context)
                    .load(Constants.MAIN_BASE_URL + it)
                    .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.RESOURCE))
                    .into(itemView.rowMain_img)
            }
            model.title.let { itemView.rowMain_title.text = it }
        }
}

How can I fix it?

How can I fix it?

ViewHolder is destroyed after you scroll it down or up (making not visible). You should store timer value when it is destroyed and restore value when it is visible again.

Welcome to the recyclerview architecture!

First of all you ought to understand that onBindViewHolder can be called multiple times when a view is scrolled out and in from your screen, and you are starting a timer in every call.
What you should do is to save the timer remaining millis in onTick in the viewHolder data and start a timer with this remaining time.

Update:

In your viewHolder class, use a long variable that represents how much time left for coutDown, lets call it timeLeft . In onTick method type holder.timeLeft = millisUntilFinished and in onFinish method type holder.timeLeft = -1 .
Now, when initiating a new timer, after checking the timer is not null check,

if (holder.leftTime > 0) {
    holder.newCountDownTimer = object : CountDownTimer(holder.timeLeft, 1000) {
        ...
    }
}

If the timeLeft is -1, decide what to do with the timer.

Also, you might need to change the ticking from every 1000 millis to smaller number, like 100 millis, for better accurate timing when saving holder.timeLeft .

Hope this will answer your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM