欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android计时器的三种实现方式(Chronometer、Timer、handler)

程序员文章站 2024-03-02 13:35:34
本文实例为大家分享了android计时器的三种方法,具体内容如下 目录: 1、借助timer实现 2、调用handler.sendmessagedely(messag...

本文实例为大家分享了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)运行结果:

Android计时器的三种实现方式(Chronometer、Timer、handler)

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)运行结果:

Android计时器的三种实现方式(Chronometer、Timer、handler)

注意:最后说一个关于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);

运行结果如下:

Android计时器的三种实现方式(Chronometer、Timer、handler)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。