• 倒计时实现方案总结 Timer Handler


    利用Timer实现倒计时

    1. @BindView(R.id.send) Button send;//发送验证码
    2. private int time = 60;//倒计时
    3. private Timer timer;
    4. private Handler handler = new Handler() {
    5. public void handleMessage(android.os.Message msg) {
    6. switch (msg.what) {
    7. case 1:
    8. send.setText(time + "S");
    9. break;
    10. case 2:
    11. send.setEnabled(true);
    12. send.setText("重新发送");
    13. break;
    14. }
    15. }
    16. };
    17. @OnClick({R.id.send, R.id.next})
    18. public void onClickIv(View v) {
    19. switch (v.getId()) {
    20. case R.id.send:
    21. send.setEnabled(false);
    22. getVerificationCode();
    23. break;
    24. }
    25. }
    26. //定时器
    27. private void setTimer() {
    28. timer = new Timer();
    29. TimerTask task = new TimerTask() {
    30. @Override
    31. public void run() {
    32. time--;
    33. if (time > 0) handler.sendEmptyMessage(1);
    34. else {
    35. handler.sendEmptyMessage(2);
    36. destoryTimer();
    37. }
    38. }
    39. };
    40. timer.schedule(task, 0, 1000);
    41. }
    42. private void destoryTimer() {
    43. if (timer != null) {
    44. timer.cancel();
    45. timer = null;
    46. }
    47. }
    48. @Override
    49. protected void onDestroy() {
    50. super.onDestroy();
    51. destoryTimer();
    52. }
    当然也可以不用Handler而用其他更精简的API,比如:
    1. TimerTask task = new TimerTask() {
    2. @Override
    3. public void run() {
    4. runOnUiThread(new Runnable() {
    5. @Override
    6. public void run() {
    7. time--;
    8. if (time > 0) send.setText(time + "S");
    9. else {
    10. send.setEnabled(true);
    11. send.setText("重新发送");
    12. destoryTimer();
    13. }
    14. }
    15. });
    16. }
    17. };

    利用Handler实现倒计时

    1. handler.sendMessageDelayed(handler.obtainMessage(1), 1000);
    2. final Handler handler = new Handler() {
    3. public void handleMessage(Message msg) {
    4. switch (msg.what) {
    5. case 1:
    6. time--;
    7. if (time > 0) {
    8. send.setText(time + "S");
    9. handler.sendMessageDelayed(handler.obtainMessage(1), 1000);
    10. } else {
    11. send.setEnabled(true);
    12. send.setText("重新发送");
    13. }
    14. }
    15. }
    16. };
    类似的实现方式
    1. Handler handler = new Handler();
    2. handler.postDelayed(runnable, 1000);
    3. Runnable runnable = new Runnable() {
    4. @Override
    5. public void run() {
    6. time--;
    7. if (time > 0) {
    8. send.setText(time + "S");
    9. handler.postDelayed(this, 1000);
    10. } else {
    11. send.setEnabled(true);
    12. send.setText("重新发送");
    13. }
    14. }
    15. };

    利用CountDownTimer实现

    1. CountDownTimer timer = new CountDownTimer(60000, 1000) {
    2. @Override
    3. public void onTick(long millisUntilFinished) {
    4. send.setText(time + "S");
    5. }
    6. @Override
    7. public void onFinish() {
    8. send.setEnabled(true);
    9. send.setText("重新发送");
    10. }
    11. };

    GitHub上星星最多的倒计时控件


    CountdownView:Android倒计时控件,使用Canvas绘制,支持多种样式
    1. compile 'com.github.iwgang:countdownview:2.1.3'
    XML
    1. <cn.iwgang.countdownview.CountdownView
    2. android:layout_width="wrap_content"
    3. android:layout_height="wrap_content" />
    基本使用
    1. CountdownView mCountdownView = (CountdownView)findViewById(R.id.countdownView);
    2. mCountdownView.start(995550000); // 毫秒
    3. // 或者自己编写倒计时逻辑,然后调用updateShow来更新UI
    4. for (int time=0; time<1000; time++) {
    5. mCountdownView.updateShow(time);
    6. }
    动态显示设置, 支持所有xml中的配置项来使用java代码设置
    1. mCountdownView.dynamicShow(DynamicConfig dynamicConfig)
    倒计时结束后回调
    1. mCountdownView.setOnCountdownEndListener(OnCountdownEndListener);
    指定间隔时间回调
    1. mCountdownView.setOnCountdownIntervalListener(long, OnCountdownIntervalListener);

    RecyclerView中倒计时方案1【最简单】

    这种方案在数据量特别小(即List的size()特别小),且刷新item及计算倒计时耗费的时间特别短时适用,否则,将会产生巨大的时间延迟。
    1、更改数据源(即重新设置倒计时剩余时间)
    1. //定时器,用于刷新GridView的数据源
    2. private void setQryTimer() {
    3. cancelQryTimer();
    4. qryTimer = new Timer();
    5. qryTimer.schedule(new TimerTask() {
    6. @Override
    7. public void run() {
    8. runOnUiThread(new Runnable() {
    9. public void run() {
    10. if (fixRpList != null && fixRpList.size() > 0) {
    11. for (FixRpBean item : fixRpList) {
    12. if (item.diff_time >= 0) item.diff_time = item.diff_time - 1000L;
    13. }
    14. if (fixRpDialog != null) fixRpDialog.upDate(fixRpList);
    15. }
    16. }
    17. });
    18. }
    19. }, 0, 1000);
    20. }
    2、刷新item(建议使用RecyclerView的局部刷新功能)
    1. public void upDate(List<FixRpBean> redPacketList) {
    2. list.clear();
    3. list.addAll(redPacketList);
    4. mRecyclerView.getAdapter().notifyDataSetChanged();//建议使用RecyclerView的局部刷新功能
    5. }

    RecyclerView中倒计时方案2【推荐】

    核心思想为:利用System.currentTimeMillis()帮我们计算倒计时。
    并且:在onViewAttachedToWindow时重新开始倒计时,在onViewDetachedFromWindow时关闭倒计时。
    1. /**
    2. * 复用 本地的计时器 —— System.currentTimeMillis(), 不必自行计时
    3. */
    4. public class RecyclerViewActivity extends Activity {
    5. private List<ItemInfo> mDataList;
    6. @Override
    7. protected void onCreate(Bundle savedInstanceState) {
    8. super.onCreate(savedInstanceState);
    9. setContentView(R.layout.activity_recyclerview);
    10. initData();
    11. RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv);
    12. recyclerView.setAdapter(new MyAdapter(this, mDataList));
    13. recyclerView.setLayoutManager(new LinearLayoutManager(this));
    14. recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
    15. recyclerView.setItemAnimator(new DefaultItemAnimator());
    16. }
    17. private void initData() {
    18. mDataList = new ArrayList<>();
    19. for (int i = 1; i < 20; i++) {
    20. mDataList.add(new ItemInfo(i * 20 * 1000));
    21. }
    22. // 校对倒计时
    23. long curTime = System.currentTimeMillis();
    24. for (ItemInfo itemInfo : mDataList) {
    25. itemInfo.endTime = curTime + itemInfo.countdown;
    26. }
    27. }
    28. static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    29. private Context mContext;
    30. private List<ItemInfo> mDatas;
    31. public MyAdapter(Context context, List<ItemInfo> datas) {
    32. this.mContext = context;
    33. this.mDatas = datas;
    34. }
    35. @Override
    36. public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    37. return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false));
    38. }
    39. @Override
    40. public void onBindViewHolder(MyViewHolder holder, int position) {
    41. holder.bindData(mDatas.get(holder.getAdapterPosition()));
    42. }
    43. @Override
    44. public int getItemCount() {
    45. return mDatas.size();
    46. }
    47. //**************************************************关键代码****************************************
    48. @Override
    49. public void onViewAttachedToWindow(MyViewHolder holder) {
    50. super.onViewAttachedToWindow(holder);//父类中为空代码
    51. holder.refreshTime(mDatas.get(holder.getAdapterPosition()).endTime - System.currentTimeMillis());
    52. }
    53. @Override
    54. public void onViewDetachedFromWindow(MyViewHolder holder) {
    55. super.onViewDetachedFromWindow(holder);
    56. holder.countdownView.stop();
    57. }
    58. //**************************************************关键代码****************************************
    59. }
    60. static class MyViewHolder extends RecyclerView.ViewHolder {
    61. public CountdownView countdownView;
    62. public MyViewHolder(View itemView) {
    63. super(itemView);
    64. countdownView = (CountdownView) itemView.findViewById(R.id.countdownView);
    65. }
    66. public void bindData(ItemInfo itemInfo) {
    67. refreshTime(itemInfo.endTime - System.currentTimeMillis());
    68. }
    69. public void refreshTime(long leftTime) {
    70. if (leftTime > 0) {
    71. countdownView.start(leftTime);
    72. } else {
    73. countdownView.stop();//停止计时器,mCustomCountDownTimer.stop();
    74. countdownView.allShowZero();//所有计时清零,即mCountdown.setTimes(0, 0, 0, 0, 0);
    75. }
    76. }
    77. }
    78. static class ItemInfo {
    79. public long countdown;
    80. /*
    81. 根据服务器返回的countdown换算成手机对应的开奖时间 (毫秒)
    82. [正常情况最好由服务器返回countdown字段,然后客户端再校对成该手机对应的时间,不然误差很大]
    83. */
    84. public long endTime;
    85. public ItemInfo(long countdown) {
    86. this.countdown = countdown;
    87. }
    88. }
    89. }

    RecyclerView中倒计时方案3【最麻烦】

    这种方案为:自己维护倒计时,再调用countdownView.updateShow来刷新显示
    并且:在onResume时开启倒计时,在onPause及onDestroy时关闭倒计时。
    个人极其不推荐这种方案,既麻烦又低效。
    1. /*
    2. 自己维护倒计时任何,再调用countdownView.updateShow来刷新显示
    3. */
    4. public class RecyclerViewActivity2 extends AppCompatActivity {
    5. private MyAdapter mMyAdapter;
    6. private List<ItemInfo> mDataList;
    7. @Override
    8. protected void onCreate(Bundle savedInstanceState) {
    9. super.onCreate(savedInstanceState);
    10. setContentView(R.layout.activity_recyclerview);
    11. initData();
    12. RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv);
    13. mMyAdapter = new RecyclerViewActivity2.MyAdapter(this, mDataList);
    14. recyclerView.setAdapter(mMyAdapter);
    15. recyclerView.setLayoutManager(new LinearLayoutManager(this));
    16. recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
    17. recyclerView.setItemAnimator(new DefaultItemAnimator());
    18. }
    19. private void initData() {
    20. mDataList = new ArrayList<>();
    21. for (int i = 1; i < 20; i++) {
    22. mDataList.add(new ItemInfo(1000 + i, "RecyclerView_测试标题_" + i, i * 20 * 1000));
    23. }
    24. // 校对倒计时
    25. long curTime = System.currentTimeMillis();
    26. for (ItemInfo itemInfo : mDataList) {
    27. itemInfo.setEndTime(curTime + itemInfo.getCountdown());
    28. }
    29. }
    30. @Override
    31. protected void onResume() {
    32. super.onResume();
    33. if (null != mMyAdapter) mMyAdapter.startRefreshTime();
    34. }
    35. @Override
    36. protected void onPause() {
    37. super.onPause();
    38. if (null != mMyAdapter) mMyAdapter.cancelRefreshTime();
    39. }
    40. @Override
    41. public void onDestroy() {
    42. super.onDestroy();
    43. if (null != mMyAdapter) mMyAdapter.cancelRefreshTime();
    44. }
    45. static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    46. private Context mContext;
    47. private List<ItemInfo> mDatas;
    48. private final SparseArray<MyViewHolder> mCountdownVHList;
    49. private Handler mHandler = new Handler();
    50. private Timer mTimer;
    51. private boolean isCancel = true;
    52. public MyAdapter(Context context, List<ItemInfo> datas) {
    53. this.mContext = context;
    54. this.mDatas = datas;
    55. mCountdownVHList = new SparseArray<>();
    56. startRefreshTime();
    57. }
    58. public void startRefreshTime() {
    59. if (!isCancel) return;
    60. if (null != mTimer) mTimer.cancel();
    61. isCancel = false;
    62. mTimer = new Timer();
    63. mTimer.schedule(new TimerTask() {
    64. @Override
    65. public void run() {
    66. mHandler.post(mRefreshTimeRunnable);
    67. }
    68. }, 0, 10);
    69. }
    70. public void cancelRefreshTime() {
    71. isCancel = true;
    72. if (null != mTimer) {
    73. mTimer.cancel();
    74. }
    75. mHandler.removeCallbacks(mRefreshTimeRunnable);
    76. }
    77. @Override
    78. public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    79. return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false));
    80. }
    81. @Override
    82. public void onBindViewHolder(MyViewHolder holder, int position) {
    83. ItemInfo curItemInfo = mDatas.get(position);
    84. holder.bindData(curItemInfo);
    85. // 处理倒计时
    86. if (curItemInfo.getCountdown() > 0) {
    87. synchronized (mCountdownVHList) {
    88. mCountdownVHList.put(curItemInfo.getId(), holder);
    89. }
    90. }
    91. }
    92. @Override
    93. public int getItemCount() {
    94. return mDatas.size();
    95. }
    96. @Override
    97. public void onViewRecycled(MyViewHolder holder) {
    98. super.onViewRecycled(holder);
    99. ItemInfo curAnnounceGoodsInfo = holder.getBean();
    100. if (null != curAnnounceGoodsInfo && curAnnounceGoodsInfo.getCountdown() > 0) {
    101. mCountdownVHList.remove(curAnnounceGoodsInfo.getId());
    102. }
    103. }
    104. private Runnable mRefreshTimeRunnable = new Runnable() {
    105. @Override
    106. public void run() {
    107. if (mCountdownVHList.size() == 0) return;
    108. synchronized (mCountdownVHList) {
    109. long currentTime = System.currentTimeMillis();
    110. int key;
    111. for (int i = 0; i < mCountdownVHList.size(); i++) {
    112. key = mCountdownVHList.keyAt(i);
    113. MyViewHolder curMyViewHolder = mCountdownVHList.get(key);
    114. if (currentTime >= curMyViewHolder.getBean().getEndTime()) {
    115. curMyViewHolder.getBean().setCountdown(0);// 倒计时结束
    116. mCountdownVHList.remove(key);
    117. notifyDataSetChanged();
    118. } else {
    119. curMyViewHolder.refreshTime(currentTime);
    120. }
    121. }
    122. }
    123. }
    124. };
    125. }
    126. static class MyViewHolder extends RecyclerView.ViewHolder {
    127. private TextView mTvTitle;
    128. private CountdownView mCvCountdownView;
    129. private ItemInfo mItemInfo;
    130. public MyViewHolder(View itemView) {
    131. super(itemView);
    132. mTvTitle = (TextView) itemView.findViewById(R.id.tv_title);
    133. mCvCountdownView = (CountdownView) itemView.findViewById(R.id.cv_countdownView);
    134. }
    135. public void bindData(ItemInfo itemInfo) {
    136. mItemInfo = itemInfo;
    137. if (itemInfo.getCountdown() > 0) {
    138. refreshTime(System.currentTimeMillis());
    139. } else {
    140. mCvCountdownView.allShowZero();
    141. }
    142. mTvTitle.setText(itemInfo.getTitle());
    143. }
    144. public void refreshTime(long curTimeMillis) {
    145. if (null == mItemInfo || mItemInfo.getCountdown() <= 0) return;
    146. mCvCountdownView.updateShow(mItemInfo.getEndTime() - curTimeMillis);
    147. }
    148. public ItemInfo getBean() {
    149. return mItemInfo;
    150. }
    151. }
    152. static class ItemInfo {
    153. private int id;
    154. private String title;
    155. private long countdown;
    156. /*
    157. 根据服务器返回的countdown换算成手机对应的开奖时间 (毫秒)
    158. [正常情况最好由服务器返回countdown字段,然后客户端再校对成该手机对应的时间,不然误差很大]
    159. */
    160. private long endTime;
    161. public ItemInfo(int id, String title, long countdown) {
    162. this.id = id;
    163. this.title = title;
    164. this.countdown = countdown;
    165. }
    166. public int getId() {
    167. return id;
    168. }
    169. public void setId(int id) {
    170. this.id = id;
    171. }
    172. public String getTitle() {
    173. return title;
    174. }
    175. public void setTitle(String title) {
    176. this.title = title;
    177. }
    178. public long getCountdown() {
    179. return countdown;
    180. }
    181. public void setCountdown(long countdown) {
    182. this.countdown = countdown;
    183. }
    184. public long getEndTime() {
    185. return endTime;
    186. }
    187. public void setEndTime(long endTime) {
    188. this.endTime = endTime;
    189. }
    190. }
    191. }
    2017-6-12




  • 相关阅读:
    7 文件操作
    初识字典1
    软件工程学习进度
    AAAA
    软件工程期末总结
    【操作系统】实验四 主存空间的分配和回收 截止提交时间:2016.6.17
    约教网站开发(一)
    操作系统实验三
    .Scrum团队成立
    数学精灵改进
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/7897ca6555535885bc83fe27d207a9b4.html
Copyright © 2020-2023  润新知