关于倒计时的实现,可以说有很多的方法,比较常见的就是Timer+TimerTask+Handler了,或者还可以配合Runnable。例如下面的代码:

[html] view plain copy
  1. importjava.util.Timer;
  2. importjava.util.TimerTask;
  3. importandroid.app.Activity;
  4. importandroid.os.Bundle;
  5. importandroid.os.Handler;
  6. importandroid.os.Message;
  7. importandroid.util.Log;
  8. importandroid.view.View;
  9. importandroid.widget.Button;
  10. importandroid.widget.TextView;
  11. publicclassMainActivityextendsActivity{
  12. Timertimer;
  13. @Override
  14. publicvoidonCreate(BundlesavedInstanceState){
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.main);
  17. finalTextViewtv=(TextView)findViewById(R.id.textView1);
  18. Buttonb=(Button)findViewById(R.id.button1);
  19. //定义Handler
  20. finalHandlerhandler=newHandler(){
  21. @Override
  22. publicvoidhandleMessage(Messagemsg){
  23. super.handleMessage(msg);
  24. //handler处理消息
  25. if(msg.what>0){
  26. tv1.setText(""+msg.what);
  27. }else{
  28. //在handler里可以更改UI组件
  29. tv.setText("倒时");
  30. timer.cancel();
  31. }
  32. }
  33. };
  34. b.setOnClickListener(newView.OnClickListener(){
  35. @Override
  36. publicvoidonClick(Viewarg0){
  37. //定义计时器
  38. timer=newTimer();
  39. //定义计划任务,根据参数的不同可以完成以下种类的工作:在固定时间执行某任务,在固定时间开始重复执行某任务,重复时间间隔可控,在延迟多久后执行某任务,在延迟多久后重复执行某任务,重复时间间隔可控
  40. timer.schedule(newTimerTask(){
  41. inti=10;
  42. //TimerTask是个抽象类,实现的是Runable类
  43. @Override
  44. publicvoidrun(){
  45. //定义一个消息传过去
  46. Messagemsg=newMessage();
  47. msg.what=i--;
  48. handler.sendMessage(msg);
  49. }
  50. },1000,200);
  51. }
  52. });
  53. }
  54. }

基本逻辑就是这样,需要注意一点是 timer.schedule(task,1000,5000),如果设置为 timer.schedule(task,5000)是不会工作的。因为timer.schedule(task,5000) 是表示执行一次的任务。timer.schedule(task,1000,5000)表示1 秒钟后开始 5 秒钟为周期 的重复执行任务。

这个例子北京简单,下面给出一个完整的例子:

[html] view plain copy
  1. importjava.util.Timer;
  2. importjava.util.TimerTask;
  3. importcom.example.jishiqi.SaveRun;
  4. importandroid.app.Activity;
  5. importandroid.app.AlertDialog;
  6. importandroid.content.DialogInterface;
  7. importandroid.os.Bundle;
  8. importandroid.os.Handler;
  9. importandroid.os.Message;
  10. importandroid.view.View;
  11. importandroid.view.View.OnClickListener;
  12. importandroid.widget.Button;
  13. importandroid.widget.TextView;
  14. publicclassMainActivityextendsActivity{
  15. Buttonbtnselecttime,daojishijicubutton;
  16. TextViewtvTime;
  17. privateTimertimer=null;
  18. privateTimerTasktask=null;
  19. privateHandlerhandler=null;
  20. privateMessagemsg=null;
  21. floatpredegree=0;
  22. floatsecondpredegree=0;
  23. floathourpredegree=0;
  24. intmlCount=-1;
  25. @Override
  26. publicvoidonCreate(Bundleicicle){
  27. super.onCreate(icicle);
  28. setContentView(R.layout.main);
  29. btnselecttime=(Button)findViewById(R.id.daojishistartbutton);
  30. daojishijicubutton=(Button)findViewById(R.id.daojishijicubutton);
  31. tvTime=(TextView)findViewById(R.id.daojishitvTime);
  32. SaveRun.setisdaojishi(false);
  33. handler=newHandler(){
  34. @Override
  35. publicvoidhandleMessage(Messagemsg){
  36. switch(msg.what){
  37. case1:
  38. mlCount--;
  39. if(mlCount<=0){
  40. enddaojishi();
  41. }
  42. inttotalSec=0;
  43. intyushu=0;
  44. totalSec=(int)(mlCount/10);
  45. yushu=(int)(mlCount%10);
  46. intmin=(totalSec/60);
  47. intsec=(totalSec%60);
  48. try{
  49. tvTime.setText(String.format("%1$02d:%2$02d.%3$d",min,
  50. sec,yushu));
  51. predegree=(float)(0.6*mlCount);
  52. secondpredegree=(float)(36.0*mlCount);
  53. hourpredegree=(float)(mlCount/100);
  54. }catch(Exceptione){
  55. tvTime.setText(""+min+":"+sec+"."+yushu);
  56. e.printStackTrace();
  57. }
  58. break;
  59. default:
  60. break;
  61. }
  62. super.handleMessage(msg);
  63. }
  64. };
  65. }
  66. privatevoidenddaojishi(){
  67. try{
  68. task.cancel();
  69. task=null;
  70. timer.cancel();
  71. timer.purge();
  72. timer=null;
  73. handler.removeMessages(msg.what);
  74. newAlertDialog.Builder(MainActivity.this)
  75. .setTitle("提示")
  76. .setMessage("倒计时结束")
  77. .setPositiveButton("确定",
  78. newDialogInterface.OnClickListener(){
  79. @Override
  80. publicvoidonClick(DialogInterfacedialog,
  81. intwhich){
  82. dialog.cancel();
  83. mlCount=600;
  84. btnselecttime.setText("开始");
  85. SaveRun.setisdaojishi(false);
  86. }
  87. }).setCancelable(false).create().show();
  88. }catch(Exceptione){
  89. e.printStackTrace();
  90. }
  91. }
  92. @Override
  93. protectedvoidonStart(){
  94. daojishijicubutton.setOnClickListener(newOnClickListener(){
  95. @Override
  96. publicvoidonClick(Viewv){
  97. predegree=0;
  98. secondpredegree=0;
  99. hourpredegree=0;
  100. mlCount=-1;
  101. btnselecttime.setText("开始");
  102. SaveRun.setisdaojishi(false);
  103. try{
  104. if(task!=null){
  105. task.cancel();
  106. task=null;
  107. timer.cancel();
  108. timer.purge();
  109. timer=null;
  110. handler.removeMessages(msg.what);
  111. }
  112. }catch(Exceptione){
  113. e.printStackTrace();
  114. }
  115. }
  116. });
  117. btnselecttime.setOnClickListener(newOnClickListener(){
  118. @Override
  119. publicvoidonClick(Viewarg0){
  120. if(null==timer){
  121. if(mlCount==-1||mlCount==0){
  122. mlCount=600;
  123. }
  124. if(mlCount>0){
  125. SaveRun.setisdaojishi(true);
  126. btnselecttime.setText("暂停");
  127. if(null==task){
  128. task=newTimerTask(){
  129. @Override
  130. publicvoidrun(){
  131. if(null==msg){
  132. msg=newMessage();
  133. }else{
  134. msg=Message.obtain();
  135. }
  136. msg.what=1;
  137. handler.sendMessage(msg);
  138. }
  139. };
  140. }
  141. timer=newTimer(true);
  142. timer.schedule(task,100,100);
  143. }
  144. }else{
  145. try{
  146. SaveRun.setisdaojishi(false);
  147. btnselecttime.setText("继续");
  148. task.cancel();
  149. task=null;
  150. timer.cancel();
  151. timer.purge();
  152. timer=null;
  153. handler.removeMessages(msg.what);
  154. }catch(Exceptione){
  155. e.printStackTrace();
  156. }
  157. }
  158. }
  159. });
  160. super.onStart();
  161. }
  162. }

布局:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <TextView
  7. android:id="@+id/daojishitvTime"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_above="@+id/daojishibuttonlinear"
  11. android:layout_centerInParent="true"
  12. android:text="00:00.0"
  13. android:textSize="35sp"
  14. android:textStyle="bold"/>
  15. <LinearLayout
  16. android:id="@+id/daojishibuttonlinear"
  17. android:layout_width="match_parent"
  18. android:layout_height="wrap_content"
  19. android:layout_alignParentBottom="true"
  20. android:orientation="vertical">
  21. <LinearLayout
  22. android:layout_width="match_parent"
  23. android:layout_height="74sp"
  24. android:background="@drawable/v5_bottom_bar_bg_light"
  25. android:orientation="horizontal">
  26. <Button
  27. android:id="@+id/daojishistartbutton"
  28. android:layout_width="wrap_content"
  29. android:layout_height="50sp"
  30. android:layout_gravity="center_vertical"
  31. android:layout_marginLeft="8sp"
  32. android:layout_marginRight="3sp"
  33. android:layout_weight="1"
  34. android:background="@drawable/startbutton"
  35. android:text="开始"/>
  36. <Button
  37. android:id="@+id/daojishijicubutton"
  38. android:layout_width="wrap_content"
  39. android:layout_height="50sp"
  40. android:layout_gravity="center_vertical"
  41. android:layout_marginLeft="3sp"
  42. android:layout_marginRight="8sp"
  43. android:layout_weight="1"
  44. android:background="@drawable/startbutton"
  45. android:text="取消"/>
  46. </LinearLayout>
  47. </LinearLayout>
  48. </RelativeLayout>



显然,这个方式比较笨拙,我们可以对此进行一个封装,利用Handler和Eunnable,看下面的代码:

[html] view plain copy
  1. packagecom.example.daojishi;
  2. importandroid.os.Handler;
  3. importandroid.util.Log;
  4. publicclassMyCountDownTimer{
  5. privatelongmillisInFuture;
  6. privatelongcountDownInterval;
  7. privatebooleanstatus;
  8. publicMyCountDownTimer(longpMillisInFuture,longpCountDownInterval){
  9. this.millisInFuture=pMillisInFuture;
  10. this.countDownInterval=pCountDownInterval;
  11. status=false;
  12. Initialize();
  13. }
  14. publicvoidStop(){
  15. status=false;
  16. }
  17. publiclonggetCurrentTime(){
  18. returnmillisInFuture;
  19. }
  20. publicvoidStart(){
  21. status=true;
  22. }
  23. publicvoidInitialize(){
  24. finalHandlerhandler=newHandler();
  25. Log.v("status","starting");
  26. finalRunnablecounter=newRunnable(){
  27. publicvoidrun(){
  28. longsec=millisInFuture/1000;
  29. if(status){
  30. if(millisInFuture<=0){
  31. Log.v("status","done");
  32. }else{
  33. Log.v("status",Long.toString(sec)+"secondsremain");
  34. millisInFuture-=countDownInterval;
  35. handler.postDelayed(this,countDownInterval);
  36. }
  37. }else{
  38. Log.v("status",Long.toString(sec)
  39. +"secondsremainandtimerhasstopped!");
  40. handler.postDelayed(this,countDownInterval);
  41. }
  42. }
  43. };
  44. handler.postDelayed(counter,countDownInterval);
  45. }
  46. }

这个类就是负责倒计时的类,下面结合Activity,看一下怎么用:

[html] view plain copy
  1. packagecom.example.daojishi;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.os.Handler;
  5. importandroid.util.Log;
  6. importandroid.view.View;
  7. importandroid.widget.Button;
  8. importandroid.widget.TextView;
  9. publicclassCounterActivityextendsActivity{
  10. /**Calledwhentheactivityisfirstcreated.*/
  11. TextViewtimeText;
  12. ButtonstartBut;
  13. ButtonstopBut;
  14. MyCountDownTimermycounter;
  15. @Override
  16. publicvoidonCreate(BundlesavedInstanceState){
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.main);
  19. timeText=(TextView)findViewById(R.id.time);
  20. startBut=(Button)findViewById(R.id.start);
  21. stopBut=(Button)findViewById(R.id.stop);
  22. mycounter=newMyCountDownTimer(20000,1000);
  23. RefreshTimer();
  24. }
  25. publicvoidStartTimer(Viewv){
  26. Log.v("startbutton","开始倒计时");
  27. mycounter.Start();
  28. }
  29. publicvoidStopTimer(Viewv){
  30. Log.v("stopbutton","暂停倒计时");
  31. mycounter.Stop();
  32. }
  33. publicvoidRefreshTimer(){
  34. finalHandlerhandler=newHandler();
  35. finalRunnablecounter=newRunnable(){
  36. publicvoidrun(){
  37. timeText.setText(Long.toString(mycounter.getCurrentTime()));
  38. handler.postDelayed(this,100);
  39. }
  40. };
  41. handler.postDelayed(counter,100);
  42. }
  43. }

布局文件:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical"
  6. android:weightSum="1">
  7. <TextView
  8. android:id="@+id/time"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="TextView"
  12. android:textAppearance="?android:attr/textAppearanceLarge">
  13. </TextView>
  14. <Button
  15. android:id="@+id/start"
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:onClick="StartTimer"
  19. android:text="Start">
  20. </Button>
  21. <Button
  22. android:id="@+id/stop"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:onClick="StopTimer"
  26. android:text="Stop">
  27. </Button>
  28. </LinearLayout>

这样就可以比较方便地使用倒计时功能了。但是还有一个更简单的方法。

在Android中有一个CountDownTimer类,这个类就是用来实现类似倒计时方面的功能。使用的时候,只需要继承自CountDownTimer并实现它的方法。

[html] view plain copy
  1. importandroid.app.Activity;
  2. importandroid.os.Bundle;
  3. importandroid.content.Intent;
  4. importandroid.os.CountDownTimer;
  5. importandroid.widget.TextView;
  6. importandroid.widget.Toast;
  7. publicclassNewActivityextendsActivity{
  8. privateMyCountmc;
  9. privateTextViewtv;
  10. @Override
  11. protectedvoidonCreate(BundlesavedInstanceState){
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.main);
  14. tv=(TextView)findViewById(R.id.show);
  15. mc=newMyCount(30000,1000);
  16. mc.start();
  17. }
  18. /*定义一个倒计时的内部类*/
  19. classMyCountextendsCountDownTimer{
  20. publicMyCount(longmillisInFuture,longcountDownInterval){
  21. super(millisInFuture,countDownInterval);
  22. }
  23. @Override
  24. publicvoidonFinish(){
  25. tv.setText("done");
  26. }
  27. @Override
  28. publicvoidonTick(longmillisUntilFinished){
  29. tv.setText("secondsremaining:"+millisUntilFinished/1000);
  30. }
  31. }
  32. }

onFinish()方法是本次倒计时结束的时候调用的,onTick是每隔1秒钟执行的,我们就是在这里执行重复的任务,像本例子的显示时间。执行完后会自动取消,如果在期间停止的话,可以调用cancel()方法。看一下它的源码就会发现,它是使用Handler+SystemClock来实现的。

[html] view plain copy
  1. /*
  2. *Copyright(C)2008TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packageandroid.os;
  17. importandroid.util.Log;
  18. /**
  19. *Scheduleacountdownuntilatimeinthefuture,with
  20. *regularnotificationsonintervalsalongtheway.
  21. *
  22. *Exampleofshowinga30secondcountdowninatextfield:
  23. *
  24. *<preclass="prettyprint">
  25. *newCountDownTimer(30000,1000){
  26. *
  27. *publicvoidonTick(longmillisUntilFinished){
  28. *mTextField.setText("secondsremaining:"+millisUntilFinished/1000);
  29. *}
  30. *
  31. *publicvoidonFinish(){
  32. *mTextField.setText("done!");
  33. *}
  34. *}.start();
  35. *</pre>
  36. *
  37. *Thecallsto{@link#onTick(long)}aresynchronizedtothisobjectsothat
  38. *onecallto{@link#onTick(long)}won'teveroccurbeforetheprevious
  39. *callbackiscomplete.Thisisonlyrelevantwhentheimplementationof
  40. *{@link#onTick(long)}takesanamountoftimetoexecutethatissignificant
  41. *comparedtothecountdowninterval.
  42. */
  43. publicabstractclassCountDownTimer{
  44. /**
  45. *Millissinceepochwhenalarmshouldstop.
  46. */
  47. privatefinallongmMillisInFuture;
  48. /**
  49. *Theintervalinmillisthattheuserreceivescallbacks
  50. */
  51. privatefinallongmCountdownInterval;
  52. privatelongmStopTimeInFuture;
  53. /**
  54. *@parammillisInFutureThenumberofmillisinthefuturefromthecall
  55. *to{@link#start()}untilthecountdownisdoneand{@link#onFinish()}
  56. *iscalled.
  57. *@paramcountDownIntervalTheintervalalongthewaytoreceive
  58. *{@link#onTick(long)}callbacks.
  59. */
  60. publicCountDownTimer(longmillisInFuture,longcountDownInterval){
  61. mMillisInFuture=millisInFuture;
  62. mCountdownInterval=countDownInterval;
  63. }
  64. /**
  65. *Cancelthecountdown.
  66. */
  67. publicfinalvoidcancel(){
  68. mHandler.removeMessages(MSG);
  69. }
  70. /**
  71. *Startthecountdown.
  72. */
  73. publicsynchronizedfinalCountDownTimerstart(){
  74. if(mMillisInFuture<=0){
  75. onFinish();
  76. returnthis;
  77. }
  78. mStopTimeInFuture=SystemClock.elapsedRealtime()+mMillisInFuture;
  79. mHandler.sendMessage(mHandler.obtainMessage(MSG));
  80. returnthis;
  81. }
  82. /**
  83. *Callbackfiredonregularinterval.
  84. *@parammillisUntilFinishedTheamountoftimeuntilfinished.
  85. */
  86. publicabstractvoidonTick(longmillisUntilFinished);
  87. /**
  88. *Callbackfiredwhenthetimeisup.
  89. */
  90. publicabstractvoidonFinish();
  91. privatestaticfinalintMSG=1;
  92. //handlescountingdown
  93. privateHandlermHandler=newHandler(){
  94. @Override
  95. publicvoidhandleMessage(Messagemsg){
  96. synchronized(CountDownTimer.this){
  97. finallongmillisLeft=mStopTimeInFuture-SystemClock.elapsedRealtime();
  98. if(millisLeft<=0){
  99. onFinish();
  100. }elseif(millisLeft<mCountdownInterval){
  101. //notick,justdelayuntildone
  102. sendMessageDelayed(obtainMessage(MSG),millisLeft);
  103. }else{
  104. longlastTickStart=SystemClock.elapsedRealtime();
  105. onTick(millisLeft);
  106. //takeintoaccountuser'sonTicktakingtimetoexecute
  107. longdelay=lastTickStart+mCountdownInterval-SystemClock.elapsedRealtime();
  108. //specialcase:user'sonTicktookmorethanintervalto
  109. //complete,skiptonextinterval
  110. while(delay<0)delay+=mCountdownInterval;
  111. sendMessageDelayed(obtainMessage(MSG),delay);
  112. }
  113. }
  114. }
  115. };
  116. }

所以,如果你的程序需要执行一些周期性的任务,就可以考虑使用CountDownTimer这个类了。需要注意的是,在上面的这个例子中,最后显示时间是1,也就是说其实上执行了29次。所以这个地方一定要注意,如果你的任务次数是n,那么设置的时候一定要注意设置成n+1的时间。

最后,欢迎大家评论交流,谢谢。

更多相关文章

  1. Android自定义闹钟
  2. Android:activity,fragment和service之我见(准备更新)
  3. 关于com.actionbarsherlock.widget.SearchView的使用无法调用Sea
  4. Android(安卓)自定义View实现波浪动画
  5. Android(安卓)日期和时间的使用实例详解
  6. Android(安卓)自定义Application
  7. 用Activity实现定制化的Dialog
  8. Android(安卓)ARouter路由中传对象遇到的坑
  9. ActivityGroup返回键获取焦点处理

随机推荐

  1. Tiny4412_android5.0.2编译
  2. Android Java和JavaScript代码相互调用
  3. android中使用Intent在activity之间传递
  4. android中各种permissiond详解
  5. Android Studio SVN 使用方法
  6. Android(安卓)命令行打包和签名
  7. android EditView ime
  8. Android Bitmap理解
  9. android中对服务的应用管理
  10. i-jetty环境搭配与编译