android time计时器,android 计时器的三种实现(Chronometer、Timer、handler)

目录:

1、借助Timer实现

2、调用handler.sendMessagedely(Message msg, long delayMillis)

3、借助布局Chronometer

1、借助Timer实现

(1) 布局文件

071b9c07855ff108dbf93e9ebb883df3.png

ef0b22e376e38997e907b437a93e4cfe.png

1

2 3 android:layout_width="match_parent"

4 android:layout_height="match_parent"

5 android:orientation="vertical" >

6

7

9 android:layout_width="wrap_content"

10 android:layout_height="wrap_content"

11 android:layout_gravity="center_horizontal"

12 android:textSize="60sp" />

13

14

chrono.xml

布局文件很简单,就是一个TextView用来显示计时时间。下面看一下Activity里的逻辑实现:

(2)Activity文件

071b9c07855ff108dbf93e9ebb883df3.png

ef0b22e376e38997e907b437a93e4cfe.png

1 public class MyChronometer extendsActivity {2 privateTextView timerView;3 private longbaseTimer;4

5 @Override6 protected voidonCreate(Bundle savedInstanceState) {7 setContentView(R.layout.chrono);8 MyChronometer.this.baseTimer =SystemClock.elapsedRealtime();9 timerView = (TextView) this.findViewById(R.id.timerView);10 final Handler startTimehandler = newHandler(){11 public voidhandleMessage(android.os.Message msg) {12 if (null !=timerView) {13 timerView.setText((String) msg.obj);14 }15 }16 };17 new Timer("开机计时器").scheduleAtFixedRate(newTimerTask() {18 @Override19 public voidrun() {20 int time = (int)((SystemClock.elapsedRealtime() - MyChronometer.this.baseTimer) / 1000);21 String hh = new DecimalFormat("00").format(time / 3600);22 String mm = new DecimalFormat("00").format(time % 3600 / 60);23 String ss = new DecimalFormat("00").format(time % 60);24 String timeFormat = new String(hh + ":" + mm + ":" +ss);25 Message msg = newMessage();26 msg.obj =timeFormat;27 startTimehandler.sendMessage(msg);28 }29

30 }, 0, 1000L);31 super.onCreate(savedInstanceState);32 }

MyChronometer.java

新开一个定时器(Timer), 在子线程中获取开机时间并转成字符串格式, 利用handler传回UI线程显示。

(3)运行结果:

b5269ca4ecd0e92c19b9904d4a87d10c.png

2.调用handler.sendMessagedely(Message msg, long delayMillis)

(1) 布局文件与方法1 相同,运行结果与方法1 相同

(2)Activity文件

071b9c07855ff108dbf93e9ebb883df3.png

ef0b22e376e38997e907b437a93e4cfe.png

1 public class MyChronometer extendsActivity {2 privateTextView timerView;3 private longbaseTimer;4

5 @Override6 protected voidonCreate(Bundle savedInstanceState) {7 setContentView(R.layout.chrono);8 MyChronometer.this.baseTimer =SystemClock.elapsedRealtime();9 timerView = (TextView) this.findViewById(R.id.timerView);10 Handler myhandler = newHandler(){11 public voidhandleMessage(android.os.Message msg) {12 if (0 == MyChronometer.this.baseTimer) {13 MyChronometer.this.baseTimer =SystemClock.elapsedRealtime();14 }15

16 int time = (int)((SystemClock.elapsedRealtime() - MyChronometer.this.baseTimer) / 1000);17 String hh = new DecimalFormat("00").format(time / 3600);18 String mm = new DecimalFormat("00").format(time % 3600 / 60);19 String ss = new DecimalFormat("00").format(time % 60);20 if (null != MyChronometer.this.timerView) {21 timerView.setText(hh + ":" + mm + ":" +ss);22 }23 sendMessageDelayed(Message.obtain(this, 0x0), 1000);24 }25 };26 myhandler.sendMessageDelayed(Message.obtain(myhandler, 0x0), 1000);27 super.onCreate(savedInstanceState);28 }

MyChronometer

sendMessageDelayed (Message msg, long delayMillis):在 delayMillis/1000 秒后发送消息 msg。

在Handler 的 handleMessage()方法中调用sendMessageDelayed方法, 巧妙的实现了循环。需要注意的是,在Handler外要调用一次startTimehandler.sendMessageDelayed(Message.obtain(startTimehandler, 0x0), 1000);  以作为循环的入口。

3.借助布局Chronometer

(1) 布局文件

071b9c07855ff108dbf93e9ebb883df3.png

ef0b22e376e38997e907b437a93e4cfe.png

1 xml version="1.0" encoding="utf-8"?>

2

3 android:layout_width="match_parent"

4 android:layout_height="match_parent"

5 android:orientation="vertical" >

6

7

9 android:layout_width="wrap_content"

10 android:layout_height="wrap_content"

11 android:layout_gravity="center_horizontal"

12 android:textSize="60sp" />

13

14 LinearLayout>

chono.xml

布局Chronometer继承自TextView

(2)Activity文件

071b9c07855ff108dbf93e9ebb883df3.png

ef0b22e376e38997e907b437a93e4cfe.png

1 public class MyChronometer extendsActivity {2

3 Chronometer chronometer;4 @Override5 protected voidonCreate(Bundle savedInstanceState) {6 setContentView(R.layout.chrono);7 chronometer = (Chronometer) this.findViewById(R.id.chronometer);8 chronometer.setBase(SystemClock.elapsedRealtime());9 chronometer.start();10 super.onCreate(savedInstanceState);11 }12 }

MyChronometer.java

逻辑代码很简单,调用chronometer.start()就可以开始计时。

chronometer.setBase(long base):设置起始计时点,这里设置的是获取开机时间。

chronometer.start():以上面setBase()设置的时间点为起始点,开始计时,看一下start()的源码就知道了:

public void start() {

mStarted = true;

updateRunning();

}

调用了updateRunning(), 跟入updateRunning()方法:

1 private void updateRunning() {2 boolean running = mVisible && mStarted;3 if (running != mRunning) {4 if (running) {5 updateText(SystemClock.elapsedRealtime());6 dispatchChronometerTick();7 mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000);8 } else {9 mHandler.removeMessages(TICK_WHAT);10 }11 mRunning = running;12 }13 }14

15 private Handler mHandler = new Handler() {16 public void handleMessage(Message m) {17 if (mRunning) {18 updateText(SystemClock.elapsedRealtime());19 dispatchChronometerTick();20 sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000);21 }22 }23 };

用updateText()方法设置时间显示。 至于计时循环机制,和方法二相同,同样是调用了handler的handMessageDelayed方法。

(3)运行结果:

a7ddb5de8bda52fd22880b6188786edb.png

注意:最后说一个关于Chronometer类的常见问题,看到很多人都问用Chronometer类如何设置格式HH:MM:SS的时间。(如果您有此问题请继续看,没有问题请忽略)

问这个问题的童鞋先看一下官方文档的描述:

If the format string is null, or if you never call setFormat(), the Chronometer will simply display the timer value in "MM:SS" or "H:MM:SS" form.

也就是说默认情况下,使用的格式是"MM:SS" 或者 "H:MM:SS", 然后有童鞋又会问:那到底是"MM:SS" 还是 "H:MM:SS"。我们先看一下源码:

updateText():

071b9c07855ff108dbf93e9ebb883df3.png

ef0b22e376e38997e907b437a93e4cfe.png

1 private synchronized void updateText(longnow) {2 long seconds = now -mBase;3 seconds /= 1000;4 String text =DateUtils.formatElapsedTime(mRecycle, seconds);5

6 if (mFormat != null) {7 Locale loc =Locale.getDefault();8 if (mFormatter == null || !loc.equals(mFormatterLocale)) {9 mFormatterLocale =loc;10 mFormatter = newFormatter(mFormatBuilder, loc);11 }12 mFormatBuilder.setLength(0);13 mFormatterArgs[0] =text;14 try{15 mFormatter.format(mFormat, mFormatterArgs);16 text =mFormatBuilder.toString();17 } catch(IllegalFormatException ex) {18 if (!mLogged) {19 Log.w(TAG, "Illegal format string: " +mFormat);20 mLogged = true;21 }22 }23 }24 setText(text);25 }

updateText(long)

调用了DateUtils.formatElapsedTime, 看一下DateUtils.formatElapsedTime里面都有啥:

071b9c07855ff108dbf93e9ebb883df3.png

ef0b22e376e38997e907b437a93e4cfe.png

1 public static String formatElapsedTime(StringBuilder recycle, longelapsedSeconds) {2 Formatter f = newFormatter(sb, Locale.getDefault());3 initFormatStrings();4 if (hours > 0) {5 returnf.format(sElapsedFormatHMMSS, hours, minutes, seconds).toString();6 } else{7 returnf.format(sElapsedFormatMMSS, minutes, seconds).toString();8 }9 }

formatElapsedTime

代码较多,我就挑重点截取了,仔细看看上面哪个if(){}else{}语句,你肯定就恍然大悟了吧?

为了我们理论的正确性,将方法三 Activity中的代码稍作修改:

chronometer.setBase(-18000000);

运行结果如下:

8b6bc497379b5a6bac7160288b3a1bff.png

(最近工作中遇到相关代码异常,就学习了一下, 如果有什么错误,希望大家多多探讨和指教)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值