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

如何实现RecyclerView条目倒计时到期后移至列表底部并修复现有报错

问题修复方案

核心错误原因

  • 现有逻辑不符合需求:你调用了ItemArrayList.remove直接删除到期条目,自然无法实现移动到底部的效果
  • 位置获取时机错误:先操作列表再调用holder.adapterPosition(),此时拿到的位置已经无效,极易出现数组越界、空指针等崩溃
  • 变量作用域错误:全局共享remTime变量,多个条目同时倒计时会出现时间串位
  • 复用逻辑隐患:条目滑出屏幕被复用后,旧的倒计时没有完全销毁,会出现时间错乱、内存泄漏问题

修复后代码

onBindViewHolder逻辑

@Override
public void onBindViewHolder(@NonNull Holder holder, int position) {
    // 先销毁当前holder已有的倒计时,避免复用错乱
    if (holder.timer != null) {
        holder.timer.cancel();
        holder.timer = null;
    }
    
    ItemDet item = ItemArrayList.get(position);
    long expireTimestamp = item.getCategoryTime().toDate().getTime();
    long currentTime = System.currentTimeMillis();
    long leftTime = expireTimestamp - currentTime;

    // 已经到期的条目直接显示到期状态
    if (leftTime <= 0) {
        holder.itemView.setEnabled(false);
        holder.item_time_h.setText("Time up!");
        return;
    }

    holder.timer = new CountDownTimer(leftTime, 1000) {
        public void onTick(long millisUntilFinished) {
            // 用局部变量存储剩余时间,避免多个条目串值
            long seconds = millisUntilFinished / 1000;
            long minutes = seconds / 60;
            long hours = minutes / 60;
            long days = hours / 24;
            String remTime;
            // 优化判断逻辑,避免重复赋值
            if (days > 0) {
                remTime = days + "d, " + hours % 24 + "h";
            } else if (hours > 0) {
                remTime = hours % 24 + "h:" + minutes % 60 + "m";
            } else if (minutes > 0) {
                remTime = minutes % 60 + "m:" + seconds % 60 + "s";
            } else {
                remTime = seconds % 60 + "s";
            }
            holder.item_time_h.setText(remTime); 
        }

        public void onFinish() {
            holder.itemView.setEnabled(false);
            holder.item_time_h.setText("Time up!");
            // 先获取有效位置,再操作列表
            int currentPos = holder.getAdapterPosition();
            // 校验位置合法性,避免崩溃
            if (currentPos != RecyclerView.NO_POSITION && currentPos < ItemArrayList.size()) {
                // 取出到期条目
                ItemDet expiredItem = ItemArrayList.remove(currentPos);
                // 添加到列表末尾
                ItemArrayList.add(expiredItem);
                // 直接通知条目移动,不需要额外调用remove和范围更新
                notifyItemMoved(currentPos, ItemArrayList.size() - 1);
            }
        }
    }.start();
}

增加条目回收时的倒计时销毁逻辑

在Adapter中新增如下方法,避免内存泄漏:

@Override
public void onViewRecycled(@NonNull Holder holder) {
    super.onViewRecycled(holder);
    if (holder.timer != null) {
        holder.timer.cancel();
        holder.timer = null;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:18:02