在购物网站的促销活动中一般都有倒计时限制购物时间或者折扣的时间,这些都是如何实现的呢?
在一个安卓客户端项目中恰好遇到了类似的问题,一开始使用的是Timer与 TimerTask, 虽然此方法通用,但后来考虑在安卓中是否有更佳的方案,于是乎共找到以下五种实现方案,另外还有一种使用CountDownTimer进行计时的方面,我会在单独的文章中进行介绍
效果如图:
方法一
Timer与TimerTask(Java实现)
- public class timerTask extends Activity{
- private int recLen = 11;
- private TextView txtView;
- Timer timer = new Timer();
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.timertask);
- txtView = (TextView)findViewById(R.id.txttime);
- timer.schedule(task, 1000, 1000); // timeTask
- }
- TimerTask task = new TimerTask() {
- @Override
- public void run() {
- runOnUiThread(new Runnable() { // UI thread
- @Override
- public void run() {
- recLen--;
- txtView.setText(""+recLen);
- if(recLen < 0){
- timer.cancel();
- txtView.setVisibility(View.GONE);
- }
- }
- });
- }
- };
- }
方法二
TimerTask与Handler(不用Timer的改进型)
- public class timerTask extends Activity{
- private int recLen = 11;
- private TextView txtView;
- Timer timer = new Timer();
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.timertask);
- txtView = (TextView)findViewById(R.id.txttime);
- timer.schedule(task, 1000, 1000); // timeTask
- }
- final Handler handler = new Handler(){
- @Override
- public void handleMessage(Message msg){
- switch (msg.what) {
- case 1:
- txtView.setText(""+recLen);
- if(recLen < 0){
- timer.cancel();
- txtView.setVisibility(View.GONE);
- }
- }
- }
- };
- TimerTask task = new TimerTask() {
- @Override
- public void run() {
- recLen--;
- Message message = new Message();
- message.what = 1;
- handler.sendMessage(message);
- }
- };
- }
方法三
- Handler与Message(不用TimerTask)
- public class timerTask extends Activity{
- private int recLen = 11;
- private TextView txtView;
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.timertask);
- txtView = (TextView)findViewById(R.id.txttime);
- Message message = handler.obtainMessage(1); // Message
- handler.sendMessageDelayed(message, 1000);
- }
- final Handler handler = new Handler(){
- public void handleMessage(Message msg){ // handle message
- switch (msg.what) {
- case 1:
- recLen--;
- txtView.setText("" + recLen);
- if(recLen > 0){
- Message message = handler.obtainMessage(1);
- handler.sendMessageDelayed(message, 1000); // send message
- }else{
- txtView.setVisibility(View.GONE);
- }
- }
- super.handleMessage(msg);
- }
- };
- }
方法四
Handler与Thread(不占用UI线程)
- public class timerTask extends Activity{
- private int recLen = 0;
- private TextView txtView;
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.timertask);
- txtView = (TextView)findViewById(R.id.txttime);
- new Thread(new MyThread()).start(); // start thread
- }
- final Handler handler = new Handler(){ // handle
- public void handleMessage(Message msg){
- switch (msg.what) {
- case 1:
- recLen++;
- txtView.setText("" + recLen);
- }
- super.handleMessage(msg);
- }
- };
- public class MyThread implements Runnable{ // thread
- @Override
- public void run(){
- while(true){
- try{
- Thread.sleep(1000); // sleep 1000ms
- Message message = new Message();
- message.what = 1;
- handler.sendMessage(message);
- }catch (Exception e) {
- }
方法五
- Handler与Runnable(最简单型)
- public class timerTask extends Activity{
- private int recLen = 0;
- private TextView txtView;
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.timertask);
- txtView = (TextView)findViewById(R.id.txttime);
- runnable.run();
- }
- Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- recLen++;
- txtView.setText("" + recLen);
- handler.postDelayed(this, 1000);
- }
- };
- }
计时与倒计时
方法1,方法2和方法3,都是倒计时
方法4,方法5,都是计时
计时和倒计时,都可使用上述方法实现(代码稍加改动)
UI线程比较
方法1,方法2和方法3,都是在UI线程实现的计时;
方法4和方法5,是另开Runnable线程实现计时
实现方式比较
方法1,采用的是Java实现,即Timer和TimerTask方式;
其它四种方法,都采用了Handler消息处理
推荐使用
如果对UI线程交互要求不很高,可以选择方法2和方法3
如果考虑到UI线程阻塞,严重影响到用户体验,推荐使用方法4,另起线程单独用于计时和其它的逻辑处理
方法5,综合了前几种方法的优点,是最简的
在逛论坛的时候,看到一个网友提问,说到了CountDownTimer这个类,从名字上面大家就可以看出来,记录下载时间。将后台线程的创建和Handler队列封装成一个方便的类调用。
查看了一下官方文档,这个类及其简单,只有四个方法,上面都涉及到了onTick,onFinsh、cancel和start。其中前面两个是抽象方法,所以要重写一下。
下面是官方给的一个小例子:
- new CountdownTimer(30000, 1000) {
- public void onTick(long millisUntilFinished) {
- mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
- }
- public void onFinish() {
- mTextField.setText("done!");
- }
- }.start();
直接用的那位网友的代码,自己稍微改动了一下,一个简单的小demo。
- package cn.demo;
- import android.app.Activity;
- import android.os.Bundle;
- import android.content.Intent;
- import android.os.CountDownTimer;
- import android.widget.TextView;
- import android.widget.Toast;
- public class NewActivity extends Activity {
- private MyCount mc;
- private TextView tv;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- tv = (TextView)findViewById(R.id.show);
- mc = new MyCount(30000, 1000);
- mc.start();
- }//end func
- /*定义一个倒计时的内部类*/
- class MyCount extends CountDownTimer {
- public MyCount(long millisInFuture, long countDownInterval) {
- super(millisInFuture, countDownInterval);
- }
- @Override
- public void onFinish() {
- tv.setText("finish");
- }
- @Override
- public void onTick(long millisUntilFinished) {
- tv.setText("请等待30秒(" + millisUntilFinished / 1000 + ")...");
- Toast.makeText(NewActivity.this, millisUntilFinished / 1000 + "", Toast.LENGTH_LONG).show();//toast有显示时间延迟
- }
- }
- }
主要是重写onTick和onFinsh这两个方法,onFinish()中的代码是计时器结束的时候要做的事情;onTick(Long m)中的代码是你倒计时开始时要做的事情,参数m是直到完成的时间,构造方法MyCount()中的两个参数中,前者是倒计的时间数,后者是倒计时onTick事件响应的间隔时间,都是以毫秒为单位。例如要倒计时30秒,每秒中间间隔时间是1秒,两个参数可以这样MyCount(30000,1000)。 将后台线程的创建和Handler队列封装成为了一个方便的类调用。
当你想取消的时候使用mc.cancel()方法就行了。