Android 列表大量倒计时卡顿的解决方案

介绍了一种使用单一倒计时工具类管理多个商品秒杀倒计时的方法,避免了因大量独立计时器造成的卡顿和内存溢出问题。通过自定义View减少重绘次数,优化了性能。

如下商品列表秒杀,每一个商品都自带倒计时,如果每个商品都用timer或handler很容易出现卡顿甚至oom的情况

所以如果我只使用一个倒计时来管理这所有的时间实现起来会怎样呢?

what?一个倒计时管理这全部?想想都恐怖......

其实换个思维你会发现,一切如此简单:

我们不需要管这些时间剩多少,只需要管好每隔1秒告诉它:兄弟,过1秒了。至于别人拿这一秒干嘛,那是别人的事。

so,只需要写一个工具类,每隔一段时间回调就行了

/**
 * 每个一段时间发送回调的倒计时工具类
 * <p>
 * 一个handler管理所有的倒计时,防止创建过多的handler
 */
public class DaoJiShiUtils {

    private final HashSet<OnDaoJiShiListener> mSetListeners = new HashSet<>();

    private final int mHandlerTime;
    @Nullable
    private final Activity mActivity;

    @SuppressLint("HandlerLeak")//本代码不会出现内存泄漏
    private final Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            if (mSetListeners.size() == 0 || (mActivity != null && mActivity.isFinishing())) {
                return;
            }

            Object[] listeners = mSetListeners.toArray();
            for (Object listener : listeners) {
                //noinspection SuspiciousMethodCalls 做这一步判断是因为遍历过程中可能会被删掉
                if (mSetListeners.contains(listener)) {
                    ((OnDaoJiShiListener) listener).onZeroOneSecond();
                }
            }
            sendEmptyMessageDelayed(1, mHandlerTime);
        }
    };

    /**
     * @param activity  防止出现内存泄漏,此处强制要求传入当前Activity。不传也可以,但必须自己手动关掉{@link #stopAll}
     * @param intervals 发送间隔毫秒值,比如100表示0.1秒发一次、1000表示1秒发一次
     */
    @MainThread
    public DaoJiShiUtils(@Nullable Activity activity, int intervals) {
        mActivity = activity;
        mHandlerTime = intervals;
    }

    /**
     * 添加倒计时回调
     */
    @MainThread
    public void addTimeListener(@NonNull OnDaoJiShiListener listener) {
        if (mSetListeners.size() == 0) {
            mHandler.removeMessages(1);
            mHandler.sendEmptyMessageDelayed(1, mHandlerTime);
        }
        mSetListeners.add(listener);
    }

    /**
     * 删除倒计时
     */
    @MainThread
    public boolean removeTimeListener(@NonNull OnDaoJiShiListener listener) {
        return mSetListeners.remove(listener);
    }

    /**
     * 如果没传Activity,则需要手动停止
     */
    @MainThread
    public void stopAll() {
        mSetListeners.clear();
        mHandler.removeCallbacksAndMessages(null);
    }


    /**
     * 监听
     */
    public interface OnDaoJiShiListener {
        /**
         * 每隔一段时间回调一次
         */
        void onZeroOneSecond();
    }
}

然后只要在Activity里new一个,Adapter都使用它即可

mDjs = new DaoJiShiUtils(this, 10);
//...

//adapter的适当位置
mDjs.addTimeListener(mTimeListener);

核心逻辑虽然少,但要想真正使用需要不少代码配合,下方有demo,可自行参考使用

常见问题1:倒计时回调特别多的时候(满屏都是),导致重绘次数太多引起卡顿

由于倒计时都是固定长度固定格式的,所以我们只需要自定义一个倒计时的view(见demo的MyDaoJiShiView),数据加载好之后就不需要再requestLayout了,直接拦截掉就行

常见问题2:demo在滑动的时候似乎也有点卡

这是因为比较懒,直接用了RecyclerView的notifyDataSetChanged,并且demo的倒计时到时间的特别多,也会导致刷新次数过多而卡顿,并不是倒计时引起的卡顿,这个可以自行优化,就不多说了。

demo或直接使用地址:GitHub - weimingjue/LifeCountdownTimer: 专为大量倒计时定制的工具类,简洁而又强大(com.github.weimingjue:CountdownUtil)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值