简体   繁体   English

如何在Android上将多个countDownTimer用于recyclerView

[英]How to use multiple countDownTimer into recyclerView on Android

In my application i want use multiple CountDownerTimer for show offer times into RecyclerView . 在我的应用程序中,我想使用多个CountDownerTimer将显示提供时间放入RecyclerView
For write this application i used Kotlin language. 为了编写这个应用程序,我使用了Kotlin语言。
I write below codes, but when scrolling on recyclerView 's items start again this timer ! 我写下面的代码,但滚动到recyclerView的项目再次启动这个计时器

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 ! 我的意思是,计时器从4:19秒开始,当滚动项目时, 10秒后再次显示4:19而不是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). 向下或向上滚动(不可见)后,ViewHolder将被销毁。 You should store timer value when it is destroyed and restore value when it is visible again. 您应该在销毁时存储计时器值,并在再次可见时恢复值。

Welcome to the recyclerview architecture! 欢迎来到recyclerview架构!

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. 首先,你应该明白,当一个视图从你的屏幕滚出来时,可以多次调用onBindViewHolder ,并且你在每个调用中都会启动一个计时器。
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. 您应该做的是在viewHolder数据中将计时器剩余onTick保存在onTick中,并使用剩余时间启动计时器。

Update: 更新:

In your viewHolder class, use a long variable that represents how much time left for coutDown, lets call it timeLeft . 在你的viewHolder类中,使用一个long变量来表示coutDown剩余的时间,让我们称之为timeLeft In onTick method type holder.timeLeft = millisUntilFinished and in onFinish method type holder.timeLeft = -1 . onTick方法类型holder.timeLeft = millisUntilFinishedonFinish方法类型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. 如果timeLeft为-1,则决定如何处理计时器。

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 . 此外,您可能需要将滴答从每1000毫秒更改为较小的数字,例如100毫秒,以便在保存holder.timeLeft时更准确的计时。

Hope this will answer your question. 希望这会回答你的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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