前言

原生的倒计时功能比较简单,没有暂停和重新开始计时功能,所以仿照原生的CountDownTimer做一个更好用的倒计时功能。

自定义类

  1. public class LCountDownTimer {
  2. /**
  3. * 时间,即开始的时间,通俗来说就是倒计时总时间
  4. */
  5. private long mMillisInFuture;
  6. /**
  7. * 布尔值,表示计时器是否被取消
  8. * 只有调用cancel时才被设置为true
  9. */
  10. private boolean mCancelled = false;
  11. /**
  12. * 用户接收回调的时间间隔,一般是1秒
  13. */
  14. private long mCountdownInterval;
  15. /**
  16. * 记录暂停时候的时间
  17. */
  18. private long mStopTimeInFuture;
  19. /**
  20. * mas.what值
  21. */
  22. private static final int MSG = 520;
  23. /**
  24. * 暂停时,当时剩余时间
  25. */
  26. private long mCurrentMillisLeft;
  27. /**
  28. * 是否暂停
  29. * 只有当调用pause时,才设置为true
  30. */
  31. private boolean mPause = false;
  32. /**
  33. * 监听listener
  34. */
  35. private TimerListener mCountDownListener;
  36. /**
  37. * 是否创建开始
  38. */
  39. private boolean isStart;
  40. private LCountDownTimer(){
  41. isStart = true;
  42. }
  43. public LCountDownTimer(long millisInFuture, long countdownInterval) {
  44. long total = millisInFuture + 20;
  45. this.mMillisInFuture = total;
  46. //this.mMillisInFuture = millisInFuture;
  47. this.mCountdownInterval = countdownInterval;
  48. isStart = true;
  49. }
  50. /**
  51. * 开始倒计时,每次点击,都会重新开始
  52. */
  53. public synchronized final void start() {
  54. if (mMillisInFuture <= 0 && mCountdownInterval <= 0) {
  55. throw new RuntimeException("you must set the millisInFuture > 0 or countdownInterval >0");
  56. }
  57. mCancelled = false;
  58. long elapsedRealtime = SystemClock.elapsedRealtime();
  59. mStopTimeInFuture = elapsedRealtime + mMillisInFuture;
  60. mPause = false;
  61. mHandler.sendMessage(mHandler.obtainMessage(MSG));
  62. if (mCountDownListener!=null){
  63. mCountDownListener.onStart();
  64. }
  65. }
  66. /**
  67. * 取消计时器
  68. */
  69. public synchronized final void cancel() {
  70. if (mHandler != null) {
  71. //暂停
  72. mPause = false;
  73. mHandler.removeMessages(MSG);
  74. //取消
  75. mCancelled = true;
  76. if (mCountDownListener!=null){
  77. mCountDownListener.onCancel();
  78. }
  79. }
  80. }
  81. /**
  82. * 按一下暂停,再按一下继续倒计时
  83. */
  84. public synchronized final void pause() {
  85. if (mHandler != null) {
  86. if (mCancelled) {
  87. return;
  88. }
  89. if (mCurrentMillisLeft < mCountdownInterval) {
  90. return;
  91. }
  92. if (!mPause) {
  93. mHandler.removeMessages(MSG);
  94. mPause = true;
  95. if (mCountDownListener!=null){
  96. mCountDownListener.onPause();
  97. }
  98. }
  99. }
  100. }
  101. /**
  102. * 恢复暂停,开始
  103. */
  104. public synchronized final void resume() {
  105. if (mMillisInFuture <= 0 && mCountdownInterval <= 0) {
  106. throw new RuntimeException("you must set the millisInFuture > 0 or countdownInterval >0");
  107. }
  108. if (mCancelled) {
  109. return;
  110. }
  111. //剩余时长少于
  112. if (mCurrentMillisLeft < mCountdownInterval || !mPause) {
  113. return;
  114. }
  115. mStopTimeInFuture = SystemClock.elapsedRealtime() + mCurrentMillisLeft;
  116. mHandler.sendMessage(mHandler.obtainMessage(MSG));
  117. mPause = false;
  118. if (mCountDownListener!=null){
  119. mCountDownListener.onResume();
  120. }
  121. }
  122. @SuppressLint("HandlerLeak")
  123. private Handler mHandler = new Handler() {
  124. @Override
  125. public void handleMessage(@NonNull Message msg) {
  126. synchronized (LCountDownTimer.this) {
  127. if (mCancelled) {
  128. return;
  129. }
  130. //剩余毫秒数
  131. final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
  132. if (millisLeft <= 0) {
  133. mCurrentMillisLeft = 0;
  134. if (mCountDownListener != null) {
  135. mCountDownListener.onFinish();
  136. }
  137. } else if (millisLeft < mCountdownInterval) {
  138. mCurrentMillisLeft = 0;
  139. // 剩余时间小于一次时间间隔的时候,不再通知,只是延迟一下
  140. sendMessageDelayed(obtainMessage(MSG), millisLeft);
  141. } else {
  142. //有多余的时间
  143. long lastTickStart = SystemClock.elapsedRealtime();
  144. if (mCountDownListener != null) {
  145. mCountDownListener.onTick(millisLeft);
  146. }
  147. mCurrentMillisLeft = millisLeft;
  148. // 考虑用户的onTick需要花费时间,处理用户onTick执行的时间
  149. // 打印这个delay时间,大概是997毫秒
  150. long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
  151. // 特殊情况:用户的onTick方法花费的时间比interval长,那么直接跳转到下一次interval
  152. // 注意,在onTick回调的方法中,不要做些耗时的操作
  153. boolean isWhile = false;
  154. while (delay < 0){
  155. delay += mCountdownInterval;
  156. isWhile = true;
  157. }
  158. if (isWhile){
  159. }
  160. sendMessageDelayed(obtainMessage(MSG), delay);
  161. }
  162. }
  163. }
  164. };
  165. /**
  166. * 设置倒计时总时间
  167. * @param millisInFuture 毫秒值
  168. */
  169. public void setMillisInFuture(long millisInFuture) {
  170. long total = millisInFuture + 20;
  171. this.mMillisInFuture = total;
  172. }
  173. /**
  174. * 设置倒计时间隔值
  175. * @param countdownInterval 间隔,一般设置为1000毫秒
  176. */
  177. public void setCountdownInterval(long countdownInterval) {
  178. this.mCountdownInterval = countdownInterval;
  179. }
  180. /**
  181. * 设置倒计时监听
  182. * @param countDownListener listener
  183. */
  184. public void setCountDownListener(TimerListener countDownListener) {
  185. this.mCountDownListener = countDownListener;
  186. }
  187. }

用到的抽象类:

  1. public abstract class TimerListener {
  2. /**
  3. * 当倒计时开始
  4. */
  5. public void onStart(){
  6. }
  7. /**
  8. * 当倒计时恢复暂停
  9. */
  10. public void onResume(){
  11. }
  12. /**
  13. * 当倒计时暂停
  14. */
  15. public void onPause(){
  16. }
  17. /**
  18. * 当倒计时结束
  19. */
  20. public void onFinish(){
  21. }
  22. /**
  23. * 当倒计时取消
  24. */
  25. public void onCancel(){
  26. }
  27. /**倒计时进行中
  28. * @param millisUntilFinished 剩余时间
  29. */
  30. public abstract void onTick(long millisUntilFinished);
  31. }

使用示例

  1. class CountDownActivity: AppCompatActivity(R.layout.activity_countdown) {
  2. //初始化倒计时相关
  3. private val mLTime by lazy {
  4. LCountDownTimer(9*1000 + 100, 1000)
  5. }
  6. override fun onCreate(savedInstanceState: Bundle?) {
  7. super.onCreate(savedInstanceState)
  8. btnCountdownStart.setOnClickListener {
  9. mLTime.start()
  10. }
  11. btnCountdownPause.setOnClickListener {
  12. mLTime.pause()
  13. }
  14. btnCountdownResume.setOnClickListener {
  15. mLTime.resume()
  16. }
  17. btnCountdownCancel.setOnClickListener {
  18. mLTime.cancel()
  19. }
  20. btnCountdownStart2.setOnClickListener {
  21. mLTime.start()
  22. }
  23. //时间的监听
  24. mLTime.setCountDownListener(object :TimerListener(){
  25. override fun onTick(millisUntilFinished: Long) {
  26. Log.e(TAG, "onTick: $millisUntilFinished");
  27. tvCountDownTime.text = "倒计时: ${millisUntilFinished/1000}"
  28. }
  29. override fun onStart() {
  30. super.onStart()
  31. Log.e(TAG, "onStart: ");
  32. }
  33. override fun onResume() {
  34. super.onResume()
  35. Log.e(TAG, "onResume: ");
  36. }
  37. override fun onPause() {
  38. super.onPause()
  39. Log.e(TAG, "onPause: ");
  40. }
  41. override fun onFinish() {
  42. super.onFinish()
  43. Log.e(TAG, "onFinish: ");
  44. tvCountDownTime.text = "倒计时结束"
  45. }
  46. override fun onCancel() {
  47. super.onCancel()
  48. Log.e(TAG, "onCancel: ");
  49. tvCountDownTime.text = "倒计时取消"
  50. }
  51. })
  52. }
  53. override fun onDestroy() {
  54. super.onDestroy()
  55. mLTime.cancel()
  56. }
  57. }