Android使用RecyclerView實現列表倒計時效果

最近接到個需求,需要將列表中的優惠券到期時間剩餘兩天時,設置倒計時效果,需求到手感覺應該問題不大。

實現倒計時方法主要有兩個:
1、爲每個開始倒計時的item設置一個定時器,再做更新item處理;
2、只啓動一個定時器,然後遍歷數據,再做更新item處理。

由於之前的倒計時功能已經封裝使用了CountDownTimer類,所以我這邊就選用第一種方法實現,直接就開幹了,一波操作下來就實現了列表的倒計時效果,下圖爲模擬效果的demo,非正式項目,如圖所示:

實現過程還是比較順暢的,使用CountDownTimer類也完美解決了RecyclerView中item複用導致不同條目的時間錯亂的問題,本以爲就這樣實現了,功能來說確實算是實現了,不過當退出頁面後,發現打印的log還是在跑,這就說明退出的時候我們並沒有做取消處理,這就是遇到了內存的問題,那下面我們來看看是怎麼解決的吧!

這裏做了一箇中間頁面,點擊按鈕後跳轉到倒計時頁面,主要是模擬退出頁面後,沒有做取消處理,是否還在後臺跑,下面我們看一下主要的代碼。

代碼實現步驟:

1、模擬數據

模擬數據用的是當前時間的後20天的數據,結構類型也是datetime類型

        //模擬數據,結構類型2021-12-11 15:28:23
        List<String> dataList = new ArrayList<>();
        //獲取當前時間的月日
        Calendar now = Calendar.getInstance();
        int currentYear = now.get(Calendar.YEAR);
        int currentMonth = now.get(Calendar.MONTH) + 1;
        int currentDay = now.get(Calendar.DAY_OF_MONTH);

        for (int i = 0; i < 20; i++) {
            if ((currentDay + i) < CommonUtils.getCurrentMonthLastDay()) {
                dataList.add(currentYear + "-" + currentMonth + "-" + (currentDay + i) + " 23:59:" + i);
            } else {
                dataList.add(currentYear + "-" + (currentMonth + 1) + "-" + (currentDay + i - CommonUtils.getCurrentMonthLastDay()) + " 23:59:" + i);
            }
        }

        recycler_view.setAdapter(new TimeOutAdapter(this, dataList));

2、倒計時功能實現的TimeOutAdapter類

class TimeOutAdapter extends RecyclerView.Adapter<TimeOutAdapter.ViewHolder> {

    private Context mContext;
    private List<String> dataList;
    private SparseArray<CountDownTimerUtils> countDownMap = new SparseArray<>();

    public TimeOutAdapter(Context context, List<String> dataList) {
        this.mContext = context;
        this.dataList = dataList;
    }

    /**
     * 清空資源
     */
    public void cancelAllTimers() {
        if (countDownMap == null) {
            return;
        }
        for (int i = 0; i < countDownMap.size(); i++) {
            CountDownTimerUtils cdt = countDownMap.get(countDownMap.keyAt(i));
            if (cdt != null) {
                cdt.cancel();
            }
        }
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.time_out_view, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
        if (dataList != null && dataList.size() != 0) {
            holder.text_content.setText(dataList.get(position));

            try {
                //將數據轉換成毫秒數,其中CommonUtils是工具類
                long residueTime = CommonUtils.residueTimeout(dataList.get(position));

                //時間大於0時設置
                if (residueTime > 0) {

                    //其中CountDownTimerUtils是倒計時的工具類
                    holder.countDownTimer = CountDownTimerUtils.getCountDownTimer()
                            .setMillisInFuture(residueTime)
                            .setCountDownInterval(1000)
                            .setTickDelegate(new CountDownTimerUtils.TickDelegate() {
                                @Override
                                public void onTick(long pMillisUntilFinished) {
                                    Log.i("TAG==", "==輸出數據更新==" + pMillisUntilFinished);
                                    //更新數據
                                    holder.text_content.setText(CommonUtils.stampToDate(pMillisUntilFinished));
                                }
                            })
                            .setFinishDelegate(new CountDownTimerUtils.FinishDelegate() {
                                @Override
                                public void onFinish() {
                                    //倒計時完成
                                }
                            });

                    holder.countDownTimer.start();
                    
                    //將item的hashcode作爲key設入SparseArray中
                    countDownMap.put(holder.text_content.hashCode(), holder.countDownTimer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        private final TextView text_content;
        CountDownTimerUtils countDownTimer;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            text_content = itemView.findViewById(R.id.text_content);
        }
    }
}

在這裏我們可以注意到cancelAllTimer()這個方法,這就是用來解決內存的問題。

通過下面這行代碼,將item中的hashcode作爲key設入SparseArray中,這樣在cancelAllTimer方法中可以遍歷取出來進行倒計時取消操作。

countDownMap.put(holder.text_content.hashCode(), holder.countDownTimer);

3、退出頁面時調用cancelAllTimer()方法取消

        //取消處理
        if (timeOutAdapter != null) {
            timeOutAdapter.cancelAllTimers();
        }

這樣就可以解決這個問題啦,收工。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章