You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin开发求助:如何将倒计时器与RecyclerView Adapter关联

RecyclerView中关联倒计时器解决方案

我是Kotlin新手,正在开发一款应用,用户可通过选择Spinner中的时长并点击按钮进行分享,但目前无法在RecyclerView中显示倒计时器,希望获得帮助将倒计时器与Adapter关联。


用户提供的代码

Adapter代码

class kampanyaadapter(
    val kampanyalistesi:ArrayList<kampanya>, private val onItemClickListener: AdapterView.OnItemClickListener?,
):RecyclerView.Adapter<kampanyaadapter.paylasimholder>()

 {

private lateinit var mListener:onItemClickListenerr

interface onItemClickListenerr{
    fun onItemClick(position: Int)
}

fun setOnClickListener(listener:onItemClickListenerr){
    mListener=listener
}


class paylasimholder(itemView: View,listener:onItemClickListenerr):RecyclerView.ViewHolder(itemView) {
    var timeStamp: TextView

    init {
        timeStamp=itemView.findViewById(R.id.timestamp)
        itemView.setOnClickListener {
            listener.onItemClick(adapterPosition)

        }

    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): paylasimholder {
    val inflater=LayoutInflater.from(parent.context)
    val view=inflater.inflate(R.layout.recycler_row,parent,false)
    return paylasimholder(view,mListener)
}

override fun onBindViewHolder(holder: paylasimholder, position: Int) {
    holder.itemView.recycler_row_kullaniciadi.text=kampanyalistesi[position].kullaniciadi
    holder.itemView.recycler_row_aciklama.text=kampanyalistesi[position].aciklama

    holder.bind(onItemClickListener)

    if (kampanyalistesi[position].downloadurl!=null){
        holder.itemView.recycler_row_imageview.visibility=View.VISIBLE
        Picasso.get().load(kampanyalistesi[position].downloadurl).into(holder.itemView.recycler_row_imageview)
    }
}

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

创建活动(kampanyaolustur)代码

class kampanyaolustur  : AppCompatActivity() , AdapterView.OnItemSelectedListener{
var secilengorsel: Uri? = null
var secilenbitmap: Bitmap? = null

var countDownTimers: Array<CountDownTimer?>?=null
private lateinit var kampanyaadapterr: kampanyaadapter

var button: Button? = null
var spinner: Spinner? = null
var textView: TextView? = null
var item: String? = null
var member: Member? = null
var sureler = arrayOf<String?>("Choose time", "yarim saat", "1 saat", "3 saat")

private lateinit var storage: FirebaseStorage
private lateinit var database: FirebaseFirestore
val db = Firebase.firestore

private lateinit var auth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_kampanyaolustur)

    auth = Firebase.auth
    storage = FirebaseStorage.getInstance()
    database = FirebaseFirestore.getInstance()

    textView = findViewById(R.id.textView2)
    button = findViewById(R.id.button)
    spinner = findViewById(R.id.spinner_id)
    spinner?.setOnItemSelectedListener(this)
    member = Member()
    val arrayAdapter: ArrayAdapter<*> =
        ArrayAdapter<Any?>(this, android.R.layout.simple_spinner_dropdown_item, sureler)
    arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
    spinner?.setAdapter(arrayAdapter)
}

override fun onItemSelected(adapterView: AdapterView<*>?, view: View, i: Int, l: Long) {
    item = spinner!!.selectedItem.toString()
    textView!!.text = item
}

override fun onNothingSelected(adapterView: AdapterView<*>?) {}

fun SaveValue(item: String?) {
    if (item == "Choose time") {
        Toast.makeText(this, "süre seçiniz", Toast.LENGTH_LONG).show()
    } else if(item=="yarim saat") {
        countDownTimers = arrayOf(object : CountDownTimer(1800000, 1000) {
            override fun onTick(millisUntilFinished: Long) {
                var diff = millisUntilFinished
                val secondsInMilli: Long = 1000
                val minutesInMilli = secondsInMilli * 60
                val hoursInMilli = minutesInMilli * 60

                val elapsedHours = diff / hoursInMilli
                diff %= hoursInMilli

                val elapsedMinutes = diff / minutesInMilli
                diff %= minutesInMilli

                val elapsedSeconds = diff / secondsInMilli

                textView2.text = "$elapsedHours saat $elapsedMinutes dakika $elapsedSeconds saniye"
            }

            override fun onFinish() {
                textView2.text = "kampanya süresi doldu!"
            }
        }.start())
        Toast.makeText(this, "süre alındı", Toast.LENGTH_LONG).show()
    }
}

fun paylasimyap(view: View) {
    SaveValue(item)
}
}

主页活动(anasayfa)代码

class anasayfa : AppCompatActivity() {
private lateinit var auth : FirebaseAuth

val db=Firebase.firestore
var kampanyalistesi=ArrayList<kampanya>()
private lateinit var recyclerviewadapter:kampanyaadapter
private lateinit var countDownTimer:CountDownTimer
var onItemClickListener:AdapterView.OnItemClickListener?=null
val onItemClick:AdapterView.OnItemClickListener?=null
var countDownTimers: Array<CountDownTimer?>?=null

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    val menuInflater=menuInflater
    menuInflater.inflate(R.menu.menu,menu)
    return super.onCreateOptionsMenu(menu)

    val layoutManager=LinearLayoutManager(this)
    recyclerView.layoutManager=layoutManager
    recyclerviewadapter= kampanyaadapter(kampanyalistesi,onItemClickListener,countDownTimers)
    recyclerView.adapter=recyclerviewadapter
    recyclerviewadapter.setOnClickListener(object :kampanyaadapter.onItemClickListenerr{
        override fun onItemClick(position: Int) {
            val intent= Intent(applicationContext, profil::class.java)
            startActivity(intent)
        }
    })
}

recyclerviewadapter.notifyDataSetChanged()
}

解决方案

1. 改造数据模型

在kampanya类中添加结束时间戳字段,持久化倒计时结束时间,避免页面重建后倒计时丢失:

class kampanya(
    var kullaniciadi: String? = null,
    var aciklama: String? = null,
    var downloadurl: String? = null,
    var endTimeMillis: Long? = null // 新增:倒计时结束的时间戳
)

2. 优化Adapter,让ViewHolder管理倒计时

修改Adapter,每个ViewHolder独立持有倒计时器,回收时清理避免内存泄漏:

class kampanyaadapter(
    val kampanyalistesi: ArrayList<kampanya>,
    private val onItemClickListener: AdapterView.OnItemClickListener?
) : RecyclerView.Adapter<kampanyaadapter.paylasimholder>() {

    private lateinit var mListener: onItemClickListenerr

    interface onItemClickListenerr {
        fun onItemClick(position: Int)
    }

    fun setOnClickListener(listener: onItemClickListenerr) {
        mListener = listener
    }

    class paylasimholder(itemView: View, listener: onItemClickListenerr) : RecyclerView.ViewHolder(itemView) {
        var timeStamp: TextView = itemView.findViewById(R.id.timestamp)
        var countDownTimer: CountDownTimer? = null // 每个ViewHolder独立持有倒计时器

        init {
            itemView.setOnClickListener {
                listener.onItemClick(adapterPosition)
            }
        }

        // 绑定倒计时逻辑
        fun bindCountDown(endTimeMillis: Long) {
            countDownTimer?.cancel() // 取消之前的倒计时,防止重复启动
            val currentTime = System.currentTimeMillis()
            val remainingMillis = endTimeMillis - currentTime

            if (remainingMillis <= 0) {
                timeStamp.text = "kampanya süresi doldu!"
                return
            }

            countDownTimer = object : CountDownTimer(remainingMillis, 1000) {
                override fun onTick(millisUntilFinished: Long) {
                    val hours = millisUntilFinished / (1000 * 60 * 60)
                    val minutes = (millisUntilFinished % (1000 * 60 * 60)) / (1000 * 60)
                    val seconds = (millisUntilFinished % (1000 * 60)) / 1000
                    timeStamp.text = "$hours saat $minutes dakika $seconds saniye"
                }

                override fun onFinish() {
                    timeStamp.text = "kampanya süresi doldu!"
                }
            }.start()
        }

        // 回收时清理倒计时,避免内存泄漏
        fun clearCountDown() {
            countDownTimer?.cancel()
            countDownTimer = null
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): paylasimholder {
        val inflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.recycler_row, parent, false)
        return paylasimholder(view, mListener)
    }

    override fun onBindViewHolder(holder: paylasimholder, position: Int) {
        val kampanya = kampanyalistesi[position]
        holder.itemView.recycler_row_kullaniciadi.text = kampanya.kullaniciadi
        holder.itemView.recycler_row_aciklama.text = kampanya.aciklama

        // 处理图片显示
        if (kampanya.downloadurl != null) {
            holder.itemView.recycler_row_imageview.visibility = View.VISIBLE
            Picasso.get().load(kampanya.downloadurl).into(holder.itemView.recycler_row_imageview)
        } else {
            holder.itemView.recycler_row_imageview.visibility = View.GONE
        }

        // 绑定倒计时
        kampanya.endTimeMillis?.let {
            holder.bindCountDown(it)
        } ?: run {
            holder.timeStamp.text = ""
        }
    }

    override fun onViewRecycled(holder: paylasimholder) {
        super.onViewRecycled(holder)
        holder.clearCountDown() // ViewHolder回收时停止倒计时
    }

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

3. 调整创建活动逻辑,保存结束时间戳

修改kampanyaolustur活动,将选中时长转换为结束时间戳,和其他数据一起保存到Firebase:

// 计算结束时间戳
fun SaveValue(item: String?): Long? {
    if (item == "Choose time") {
        Toast.makeText(this, "süre seçiniz", Toast.LENGTH_LONG).show()
        return null
    }
    val durationMillis = when(item) {
        "yarim saat" -> 1800000L // 30分钟
        "1 saat" -> 3600000L // 1小时
        "3 saat" -> 10800000L // 3小时
        else -> {
            Toast.makeText(this, "geçersiz süre", Toast.LENGTH_LONG).show()
            null
        }
    }
    return durationMillis?.let { System.currentTimeMillis() + it }
}

// 分享按钮点击逻辑
fun paylasimyap(view: View) {
    val endTimeMillis = SaveValue(item) ?: return

    // 构造kampanya对象,替换实际的描述等字段
    val kampanya = kampanya(
        kullaniciadi = auth.currentUser?.displayName,
        aciklama = "你的活动描述", // 替换为用户输入的描述
        downloadurl = secilengorsel?.toString(),
        endTimeMillis = endTimeMillis
    )

    // 保存到Firebase
    db.collection("kampanyalar").add(kampanya)
        .addOnSuccessListener {
            Toast.makeText(this, "kampanya paylaşıldı", Toast.LENGTH_LONG).show()
            finish()
        }
        .addOnFailureListener {
            Toast.makeText(this, "paylaşım başarısız", Toast.LENGTH_LONG).show()
        }
}

4. 主页活动获取数据并传递给Adapter

在anasayfa活动中,从Firebase获取包含结束时间戳的活动数据,更新RecyclerView:

class anasayfa : AppCompatActivity() {
    private lateinit var auth: FirebaseAuth
    val db = Firebase.firestore
    var kampanyalistesi = ArrayList<kampanya>()
    private lateinit var recyclerviewadapter: kampanyaadapter
    var onItemClickListener: AdapterView.OnItemClickListener? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_anasayfa) // 确保设置正确布局

        auth = Firebase.auth

        // 初始化RecyclerView
        val layoutManager = LinearLayoutManager(this)
        recyclerView.layoutManager = layoutManager
        recyclerviewadapter = kampanyaadapter(kampanyalistesi, onItemClickListener)
        recyclerView.adapter = recyclerviewadapter

        recyclerviewadapter.setOnClickListener(object : kampanyaadapter.onItemClickListenerr {
            override fun onItemClick(position: Int) {
                val intent = Intent(applicationContext, profil::class.java)
                startActivity(intent)
            }
        })

        // 从Firebase获取数据
        db.collection("kampanyalar")
            .addSnapshotListener { snapshot, e ->
                if (e != null) {
                    return@addSnapshotListener
                }
                kampanyalistesi.clear()
                snapshot?.documents?.forEach { document ->
                    val kampanya = document.toObject(kampanya::class.java)
                    kampanya?.let { kampanyalistesi.add(it) }
                }
                recyclerviewadapter.notifyDataSetChanged()
            }
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        val menuInflater = menuInflater
        menuInflater.inflate(R.menu.menu, menu)
        return super.onCreateOptionsMenu(menu)
    }
}

内容的提问来源于stack exchange,提问作者vertigo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:27:05