Android如何利用RecyclerView實(shí)現(xiàn)列表倒計(jì)時(shí)效果實(shí)例代碼
前言
最近面試時(shí),面試官問了一個(gè)列表倒計(jì)時(shí)效果如何實(shí)現(xiàn),然后腦袋突然懵的了O(∩_∩)O,現(xiàn)在記錄一下。
運(yùn)行效果圖

實(shí)現(xiàn)思路
實(shí)現(xiàn)方法主要有兩個(gè):
1.為每個(gè)開始倒計(jì)時(shí)的item啟動一個(gè)定時(shí)器,再做更新item處理;
2.只啟動一個(gè)定時(shí)器,然后遍歷數(shù)據(jù),再做再做更新item處理。
經(jīng)過思考,包括性能、實(shí)現(xiàn)等方面,決定使用第2種方式實(shí)現(xiàn)。
實(shí)現(xiàn)過程
數(shù)據(jù)實(shí)體
/** * 總共的倒計(jì)時(shí)的時(shí)間(結(jié)束時(shí)間-開始時(shí)間),單位:毫秒 * 例: 2019-02-23 11:00:30 與 2019-02-23 11:00:00 之間的相差的毫秒數(shù) */ private long totalTime; /** * 倒計(jì)時(shí)是否在暫停狀態(tài) */ private boolean isPause = true;
倒計(jì)時(shí)
Timer
mTimer.schedule(mTask, 0, 1000);
TimerTask
class MyTask extends TimerTask {
@Override
public void run() {
if (mList.isEmpty()) {
return;
}
int size = mList.size();
CountDownTimerBean bean;
long totalTime;
for (int i = 0; i < size; i++) {
bean = mList.get(i);
if (!bean.isPause()) {//不處于暫停狀態(tài)
totalTime = bean.getTotalTime() - 1000;
if (totalTime <= 0) {
bean.setPause(true);
bean.setTotalTime(0);
}
bean.setTotalTime(totalTime);
Message message = mHandler.obtainMessage(1);
message.arg1 = i;
mHandler.sendMessage(message);
}
}
}
}
線程交互更新item
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
notifyItemChanged(msg.arg1, "update-time");
break;
}
}
};
性能優(yōu)化方面
1.調(diào)用notifyItemChanged()方法后,不要更新整個(gè)item(比如說item包含圖片,不需要變的),所以要重寫onBindViewHolder( Holder , int , List
@Override
public void onBindViewHolder(@NonNull Holder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
return;
}
//更新某個(gè)控件,比如說只需要更新時(shí)間信息,其他不用動
CountDownTimerBean bean = mList.get(position);
long day = bean.getTotalTime() / (1000 * 60 * 60 * 24);
long hour = (bean.getTotalTime() / (1000 * 60 * 60) - day * 24);
long min = ((bean.getTotalTime() / (60 * 1000)) - day * 24 * 60 - hour * 60);
long s = (bean.getTotalTime() / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
holder.tvTime.setText("剩余時(shí)間: " + day + "天" + hour + "小時(shí)" + min + "分" + s + "秒");
holder.btnAction.setText(bean.isPause() ? "開始" : "暫停");
holder.btnAction.setEnabled(bean.getTotalTime() != 0);
}
2.銷毀資源操作:
/**
* 銷毀資源
*/
public void destroy() {
mHandler.removeMessages(1);
if (mTimer != null) {
mTimer.cancel();
mTimer.purge();
mTimer = null;
}
}
RecyclerView.Adapter部分源碼
public class CountDownTimerAdapter extends RecyclerView.Adapter<CountDownTimerAdapter.Holder> {
private static final String TAG = "CountDownTimerAdapter->";
private List<CountDownTimerBean> mList;//數(shù)據(jù)
private Handler mHandler;//線程調(diào)度,用來更新列表
private Timer mTimer;
private MyTask mTask;
public CountDownTimerAdapter() {
mList = new ArrayList<>();
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
notifyItemChanged(msg.arg1, "update-time");
break;
}
}
};
mTask = new MyTask();
}
public void bindAdapterToRecyclerView(@NonNull RecyclerView view) {
view.setAdapter(this);
}
/**
* 設(shè)置新的數(shù)據(jù)源
*
* @param list 數(shù)據(jù)
*/
public void setNewData(@NonNull List<CountDownTimerBean> list) {
destroy();
mList.clear();
mList.addAll(list);
notifyDataSetChanged();
if (mTimer == null) {
mTimer = new Timer();
}
mTimer.schedule(mTask, 0, 1000);
}
/**
* 銷毀資源
*/
public void destroy() {
mHandler.removeMessages(1);
if (mTimer != null) {
mTimer.cancel();
mTimer.purge();
mTimer = null;
}
}
@NonNull
@Override
public Holder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_count_down_timer, viewGroup, false);
return new Holder(view);
}
@Override
public void onBindViewHolder(@NonNull Holder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
return;
}
//更新某個(gè)控件,比如說只需要更新時(shí)間信息,其他不用動
CountDownTimerBean bean = mList.get(position);
long day = bean.getTotalTime() / (1000 * 60 * 60 * 24);
long hour = (bean.getTotalTime() / (1000 * 60 * 60) - day * 24);
long min = ((bean.getTotalTime() / (60 * 1000)) - day * 24 * 60 - hour * 60);
long s = (bean.getTotalTime() / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
holder.tvTime.setText("剩余時(shí)間: " + day + "天" + hour + "小時(shí)" + min + "分" + s + "秒");
holder.btnAction.setText(bean.isPause() ? "開始" : "暫停");
holder.btnAction.setEnabled(bean.getTotalTime() != 0);
}
@Override
public void onBindViewHolder(@NonNull final Holder holder, int position) {
holder.ivIcon.setImageResource(R.mipmap.ic_launcher_round);
final CountDownTimerBean bean = mList.get(position);
long day = bean.getTotalTime() / (1000 * 60 * 60 * 24);
long hour = (bean.getTotalTime() / (1000 * 60 * 60) - day * 24);
long min = ((bean.getTotalTime() / (60 * 1000)) - day * 24 * 60 - hour * 60);
long s = (bean.getTotalTime() / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
holder.tvTime.setText("剩余時(shí)間: " + day + "天" + hour + "小時(shí)" + min + "分" + s + "秒");
holder.btnAction.setText(bean.isPause() ? "開始" : "暫停");
holder.btnAction.setEnabled(bean.getTotalTime() != 0);
holder.btnAction.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (bean.isPause()) {
bean.setPause(false);
holder.btnAction.setText("暫停");
} else {
bean.setPause(true);
holder.btnAction.setText("開始");
}
}
});
}
@Override
public int getItemCount() {
return mList.size();
}
class Holder extends RecyclerView.ViewHolder {
private ImageView ivIcon;
private TextView tvTime;
private Button btnAction;
Holder(@NonNull View itemView) {
super(itemView);
ivIcon = itemView.findViewById(R.id.iv_icon);
tvTime = itemView.findViewById(R.id.tv_time);
btnAction = itemView.findViewById(R.id.btn_action);
}
}
class MyTask extends TimerTask {
@Override
public void run() {
if (mList.isEmpty()) {
return;
}
int size = mList.size();
CountDownTimerBean bean;
long totalTime;
for (int i = 0; i < size; i++) {
bean = mList.get(i);
if (!bean.isPause()) {//不處于暫停狀態(tài)
totalTime = bean.getTotalTime() - 1000;
if (totalTime <= 0) {
bean.setPause(true);
bean.setTotalTime(0);
}
bean.setTotalTime(totalTime);
Message message = mHandler.obtainMessage(1);
message.arg1 = i;
mHandler.sendMessage(message);
}
}
}
}
}
項(xiàng)目地址
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
android調(diào)用webservice接口獲取信息
這篇文章主要為大家詳細(xì)介紹了android調(diào)用webservice接口獲取信息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
Android利用SeekBar實(shí)現(xiàn)簡單音樂播放器
這篇文章主要為大家詳細(xì)介紹了Android利用SeekBar實(shí)現(xiàn)簡單音樂播放器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Android?Studio實(shí)現(xiàn)簡單補(bǔ)間動畫
這篇文章主要為大家詳細(xì)介紹了Android?Studio實(shí)現(xiàn)簡單補(bǔ)間動畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
Android 兩種方法實(shí)現(xiàn)長按返回健退出
這篇文章主要介紹了Android 兩種方法實(shí)現(xiàn)長按返回健退出的相關(guān)資料,需要的朋友可以參考下2017-02-02
Android RecyclerView仿新聞頭條的頻道管理功能
這篇文章主要介紹了Android RecyclerView仿新聞頭條的頻道管理功能,需要的朋友可以參考下2017-06-06
Android網(wǎng)絡(luò)通信的實(shí)現(xiàn)方式
這篇文章主要為大家詳細(xì)介紹了Android網(wǎng)絡(luò)通信的實(shí)現(xiàn)方式,四種實(shí)現(xiàn)網(wǎng)絡(luò)通信的方式供大家學(xué)習(xí),感興趣的小伙伴們可以參考一下2016-06-06
Android 安全加密:消息摘要Message Digest詳解
本文主要介紹Android安全加密消息摘要Message Digest,這里整理了詳細(xì)的資料,并說明如何使用Message Digest 和使用注意事項(xiàng),有需要的小伙伴可以參考下2016-09-09

