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

时间:2020-11-30 20:33:36

 目录:

1、借助Timer实现

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

3、借助布局Chronometer

 

1、借助Timer实现

(1) 布局文件

android 计时器的三种实现(Chronometer、Timer、handler)android 计时器的三种实现(Chronometer、Timer、handler)
 1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical" >
6
7 <TextView
8 android:id="@+id/timerView"
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>
android 计时器的三种实现(Chronometer、Timer、handler)

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

(2)Activity文件

android 计时器的三种实现(Chronometer、Timer、handler)android 计时器的三种实现(Chronometer、Timer、handler)
 1 public class MyChronometer extends Activity {
2 private TextView timerView;
3 private long baseTimer;
4
5 @Override
6 protected void onCreate(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 = new Handler(){
11 public void handleMessage(android.os.Message msg) {
12 if (null != timerView) {
13 timerView.setText((String) msg.obj);
14 }
15 }
16 };
17 new Timer("开机计时器").scheduleAtFixedRate(new TimerTask() {
18 @Override
19 public void run() {
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 = new Message();
26 msg.obj = timeFormat;
27 startTimehandler.sendMessage(msg);
28 }
29
30 }, 0, 1000L);
31 super.onCreate(savedInstanceState);
32 }
android 计时器的三种实现(Chronometer、Timer、handler)

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

(3)运行结果:

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

 

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

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

(2)Activity文件

android 计时器的三种实现(Chronometer、Timer、handler)android 计时器的三种实现(Chronometer、Timer、handler)
 1 public class MyChronometer extends Activity {
2 private TextView timerView;
3 private long baseTimer;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 setContentView(R.layout.chrono);
8 MyChronometer.this.baseTimer = SystemClock.elapsedRealtime();
9 timerView = (TextView) this.findViewById(R.id.timerView);
10 Handler myhandler = new Handler(){
11 public void handleMessage(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 }
android 计时器的三种实现(Chronometer、Timer、handler)

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

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

 

3.借助布局Chronometer

(1) 布局文件

android 计时器的三种实现(Chronometer、Timer、handler)android 计时器的三种实现(Chronometer、Timer、handler)
 1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical" >
6
7 <Chronometer
8 android:id="@+id/chronometer"
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>
android 计时器的三种实现(Chronometer、Timer、handler)

布局Chronometer继承自TextView

(2)Activity文件

android 计时器的三种实现(Chronometer、Timer、handler)android 计时器的三种实现(Chronometer、Timer、handler)
 1 public class MyChronometer extends Activity {
2
3 Chronometer chronometer;
4 @Override
5 protected void onCreate(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 }
android 计时器的三种实现(Chronometer、Timer、handler)

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

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

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

public void start() {
mStarted = true;
updateRunning();
}

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

android 计时器的三种实现(Chronometer、Timer、handler)
 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 };
android 计时器的三种实现(Chronometer、Timer、handler)

用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():

android 计时器的三种实现(Chronometer、Timer、handler)android 计时器的三种实现(Chronometer、Timer、handler)
 1 private synchronized void updateText(long now) {
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 = new Formatter(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 }
android 计时器的三种实现(Chronometer、Timer、handler)

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

android 计时器的三种实现(Chronometer、Timer、handler)android 计时器的三种实现(Chronometer、Timer、handler)
1  public static String formatElapsedTime(StringBuilder recycle, long elapsedSeconds) {
2 Formatter f = new Formatter(sb, Locale.getDefault());
3 initFormatStrings();
4 if (hours > 0) {
5 return f.format(sElapsedFormatHMMSS, hours, minutes, seconds).toString();
6 } else {
7 return f.format(sElapsedFormatMMSS, minutes, seconds).toString();
8 }
9 }
android 计时器的三种实现(Chronometer、Timer、handler)

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

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

 

chronometer.setBase(-18000000);

运行结果如下:
android 计时器的三种实现(Chronometer、Timer、handler)