Android计时器的三种实现方式(Chronometer、Timer、handler)
本文实例为大家分享了android计时器的三种方法,具体内容如下
目录:
1、借助timer实现
2、调用handler.sendmessagedely(message msg, long delaymillis)
3、借助布局chronometer
1、借助timer实现
(1) 布局文件
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <textview android:id="@+id/timerview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textsize="60sp" /> </linearlayout>
布局文件很简单,就是一个textview用来显示计时时间。下面看一下activity里的逻辑实现:
(2)activity文件
public class mychronometer extends activity { private textview timerview; private long basetimer; @override protected void oncreate(bundle savedinstancestate) { setcontentview(r.layout.chrono); mychronometer.this.basetimer = systemclock.elapsedrealtime(); timerview = (textview) this.findviewbyid(r.id.timerview); final handler starttimehandler = new handler(){ public void handlemessage(android.os.message msg) { if (null != timerview) { timerview.settext((string) msg.obj); } } }; new timer("开机计时器").scheduleatfixedrate(new timertask() { @override public void run() { int time = (int)((systemclock.elapsedrealtime() - mychronometer.this.basetimer) / 1000); string hh = new decimalformat("00").format(time / 3600); string mm = new decimalformat("00").format(time % 3600 / 60); string ss = new decimalformat("00").format(time % 60); string timeformat = new string(hh + ":" + mm + ":" + ss); message msg = new message(); msg.obj = timeformat; starttimehandler.sendmessage(msg); } }, 0, 1000l); super.oncreate(savedinstancestate); }
新开一个定时器(timer), 在子线程中获取开机时间并转成字符串格式, 利用handler传回ui线程显示。
(3)运行结果:
2.调用handler.sendmessagedely(message msg, long delaymillis)
(1) 布局文件与方法1 相同,运行结果与方法1 相同
(2)activity文件
public class mychronometer extends activity { private textview timerview; private long basetimer; @override protected void oncreate(bundle savedinstancestate) { setcontentview(r.layout.chrono); mychronometer.this.basetimer = systemclock.elapsedrealtime(); timerview = (textview) this.findviewbyid(r.id.timerview); handler myhandler = new handler(){ public void handlemessage(android.os.message msg) { if (0 == mychronometer.this.basetimer) { mychronometer.this.basetimer = systemclock.elapsedrealtime(); } int time = (int)((systemclock.elapsedrealtime() - mychronometer.this.basetimer) / 1000); string hh = new decimalformat("00").format(time / 3600); string mm = new decimalformat("00").format(time % 3600 / 60); string ss = new decimalformat("00").format(time % 60); if (null != mychronometer.this.timerview) { timerview.settext(hh + ":" + mm + ":" + ss); } sendmessagedelayed(message.obtain(this, 0x0), 1000); } }; myhandler.sendmessagedelayed(message.obtain(myhandler, 0x0), 1000); super.oncreate(savedinstancestate); }
sendmessagedelayed (message msg, long delaymillis):在 delaymillis/1000 秒后发送消息 msg。
在handler 的 handlemessage()方法中调用sendmessagedelayed方法, 巧妙的实现了循环。需要注意的是,在handler外要调用一次starttimehandler.sendmessagedelayed(message.obtain(starttimehandler, 0x0), 1000); 以作为循环的入口。
3.借助布局chronometer
(1) 布局文件
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <chronometer android:id="@+id/chronometer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textsize="60sp" /> </linearlayout>
布局chronometer继承自textview
(2)activity文件
public class mychronometer extends activity { chronometer chronometer; @override protected void oncreate(bundle savedinstancestate) { setcontentview(r.layout.chrono); chronometer = (chronometer) this.findviewbyid(r.id.chronometer); chronometer.setbase(systemclock.elapsedrealtime()); chronometer.start(); super.oncreate(savedinstancestate); } }
逻辑代码很简单,调用chronometer.start()就可以开始计时。
chronometer.setbase(long base):设置起始计时点,这里设置的是获取开机时间。
chronometer.start():以上面setbase()设置的时间点为起始点,开始计时,看一下start()的源码就知道了:
public void start() { mstarted = true; updaterunning(); }
调用了updaterunning(), 跟入updaterunning()方法:
private void updaterunning() { boolean running = mvisible && mstarted; if (running != mrunning) { if (running) { updatetext(systemclock.elapsedrealtime()); dispatchchronometertick(); mhandler.sendmessagedelayed(message.obtain(mhandler, tick_what), 1000); } else { mhandler.removemessages(tick_what); } mrunning = running; } } private handler mhandler = new handler() { public void handlemessage(message m) { if (mrunning) { updatetext(systemclock.elapsedrealtime()); dispatchchronometertick(); sendmessagedelayed(message.obtain(this, tick_what), 1000); } } };
用updatetext()方法设置时间显示。 至于计时循环机制,和方法二相同,同样是调用了handler的handmessagedelayed方法。
(3)运行结果:
注意:最后说一个关于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():
private synchronized void updatetext(long now) { long seconds = now - mbase; seconds /= 1000; string text = dateutils.formatelapsedtime(mrecycle, seconds); if (mformat != null) { locale loc = locale.getdefault(); if (mformatter == null || !loc.equals(mformatterlocale)) { mformatterlocale = loc; mformatter = new formatter(mformatbuilder, loc); } mformatbuilder.setlength(0); mformatterargs[0] = text; try { mformatter.format(mformat, mformatterargs); text = mformatbuilder.tostring(); } catch (illegalformatexception ex) { if (!mlogged) { log.w(tag, "illegal format string: " + mformat); mlogged = true; } } } settext(text); }
调用了dateutils.formatelapsedtime, 看一下dateutils.formatelapsedtime里面都有啥:
public static string formatelapsedtime(stringbuilder recycle, long elapsedseconds) { formatter f = new formatter(sb, locale.getdefault()); initformatstrings(); if (hours > 0) { return f.format(selapsedformathmmss, hours, minutes, seconds).tostring(); } else { return f.format(selapsedformatmmss, minutes, seconds).tostring(); } }
代码较多,我就挑重点截取了,仔细看看上面哪个if(){}else{}语句,你肯定就恍然大悟了吧?
为了我们理论的正确性,将方法三 activity中的代码稍作修改:
chronometer.setbase(-18000000);
运行结果如下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Spring的AOP极简入门