Android使用RecyclerView實現(xiàn)列表倒計時
最近接到個需求,需要將列表中的優(yōu)惠券到期時間剩余兩天時,設(shè)置倒計時效果,需求到手感覺應(yīng)該問題不大。
實現(xiàn)倒計時方法主要有兩個:
1、為每個開始倒計時的item設(shè)置一個定時器,再做更新item處理;
2、只啟動一個定時器,然后遍歷數(shù)據(jù),再做更新item處理。
由于之前的倒計時功能已經(jīng)封裝使用了CountDownTimer類,所以我這邊就選用第一種方法實現(xiàn),直接就開干了,一波操作下來就實現(xiàn)了列表的倒計時效果,下圖為模擬效果的demo,非正式項目,如圖所示:

實現(xiàn)過程還是比較順暢的,使用CountDownTimer類也完美解決了RecyclerView中item復(fù)用導(dǎo)致不同條目的時間錯亂的問題,本以為就這樣實現(xiàn)了,功能來說確實算是實現(xiàn)了,不過當(dāng)退出頁面后,發(fā)現(xiàn)打印的log還是在跑,這就說明退出的時候我們并沒有做取消處理,這就是遇到了內(nèi)存的問題,那下面我們來看看是怎么解決的吧!
這里做了一個中間頁面,點擊按鈕后跳轉(zhuǎn)到倒計時頁面,主要是模擬退出頁面后,沒有做取消處理,是否還在后臺跑,下面我們看一下主要的代碼。
代碼實現(xiàn)步驟:
1、模擬數(shù)據(jù)
模擬數(shù)據(jù)用的是當(dāng)前時間的后20天的數(shù)據(jù),結(jié)構(gòu)類型也是datetime類型
//模擬數(shù)據(jù),結(jié)構(gòu)類型2021-12-11 15:28:23List<String> dataList = new ArrayList<>();//獲取當(dāng)前時間的月日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、倒計時功能實現(xiàn)的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@Overridepublic 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;}@Overridepublic void onBindViewHolder(@NonNull final ViewHolder holder, int position) {if (dataList != null && dataList.size() != 0) {holder.text_content.setText(dataList.get(position));try {//將數(shù)據(jù)轉(zhuǎn)換成毫秒數(shù),其中CommonUtils是工具類long residueTime = CommonUtils.residueTimeout(dataList.get(position));//時間大于0時設(shè)置if (residueTime > 0) {//其中CountDownTimerUtils是倒計時的工具類holder.countDownTimer = CountDownTimerUtils.getCountDownTimer().setMillisInFuture(residueTime).setCountDownInterval(1000).setTickDelegate(new CountDownTimerUtils.TickDelegate() {@Overridepublic void onTick(long pMillisUntilFinished) {Log.i("TAG==", "==輸出數(shù)據(jù)更新==" + pMillisUntilFinished);//更新數(shù)據(jù)holder.text_content.setText(CommonUtils.stampToDate(pMillisUntilFinished));}}).setFinishDelegate(new CountDownTimerUtils.FinishDelegate() {@Overridepublic void onFinish() {//倒計時完成}});holder.countDownTimer.start();//將item的hashcode作為key設(shè)入SparseArray中countDownMap.put(holder.text_content.hashCode(), holder.countDownTimer);}} catch (Exception e) {e.printStackTrace();}}}@Overridepublic 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()這個方法,這就是用來解決內(nèi)存的問題。
通過下面這行代碼,將item中的hashcode作為key設(shè)入SparseArray中,這樣在cancelAllTimer方法中可以遍歷取出來進(jìn)行倒計時取消操作。
countDownMap.put(holder.text_content.hashCode(), holder.countDownTimer);3、退出頁面時調(diào)用cancelAllTimer()方法取消
//取消處理if (timeOutAdapter != null) {timeOutAdapter.cancelAllTimers();}
這樣就可以解決這個問題啦,收工。
需要源碼的童鞋在【龍旋】公眾號對話框回復(fù)關(guān)鍵字【倒計時】獲取
