目录:
1、借助Timer实现
2、调用handler.sendMessagedely(Message msg, long delayMillis)
3、借助布局Chronometer
1、借助Timer实现
(1) 布局文件
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文件
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)运行结果:
2.调用handler.sendMessagedely(Message msg, long delayMillis)
(1) 布局文件与方法1 相同,运行结果与方法1 相同
(2)Activity文件
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) 布局文件
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文件
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)运行结果:
注意:最后说一个关于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():
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里面都有啥:
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);
运行结果如下:
(最近工作中遇到相关代码异常,就学习了一下, 如果有什么错误,希望大家多多探讨和指教)