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
相关产品推荐
相关产品推荐

