Chronmeter

支援API level 1以上

在各種android應用中,計時器是一個滿常被使用的功能
在錄音、錄影等等應用中都能看到計時器的身影

而為了簡化開發者的麻煩,Google在android中提供了Chronmeter這個元件
讓開發者能用少量的程式碼就能使用簡易的計時器與呈現計時的結果

Chronmeter與其他計時器(像是CountDownTimer)最大不同的地方在於
Chronmeter繼承了TextView,所以本身就包含了顯示的View與相關功能
而其他計時器只有邏輯運算,並不包含顯示內容的功能

使用Chronmeter要注意的幾個地方:

  • 只能計時,不能倒數 (API level 24之後有提供倒數的API)
  • 計時以秒為單位,如果精度要到秒以下的單位就無法使用Chronmeter (除非OverrideonChronometerTick()這個方法)
  • 計時顯示的方式預設是MM:SS(分:秒),如果計時破小時的話會使用H:MM:SS(時:分:秒)

Chronmeter in XML

在layout的xml中,使用上就跟使用Textview很像,設定id、寬高之類的

 <Chronometer 
        android:id="@+id/timer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:format="現在時間-%s"/>

Chronometer中2個比較重要的XML屬性如下:

屬性 內容
android:countDown 指定Chronometer是要倒數計時(true)還是一般計時(false),這個屬性從API level 24開始支援
android:format 基本上就是指定Chronmeter在Textview中的顯示內容,但如果指定的字串內有包含"%s"的話,"%s"被會替換成計時器的時間(MM:SS),舉例來說像是上面的XML,過了42秒會顯示「現在時間-00:42」

Chronometer 常用方法

要注意的是,每呼叫一次start(),都必須對應到呼叫一次stop(),否則會造成resource leaks

函式名稱 方法說明
setBase(long base); 設置計時器的基準時間
getBase(); 得到設置的基準時間
setFormat(String format); 設置顯示時間的格式
start(); 開始計時
stop(); 停止計時

使用方式

使用Chronometer時,一般來說會先使用setBase(time)來設定一個「基準時間」
表示要從該時間開始計數,通常會使用SystemClock.elapsedRealtime()來取得基準時間
保險起見,建議在每次呼叫start()之前都使用setBase(time)設定基準時間
以確保每次的計時基準時間都有更新,都是從現在開始計時

在android中,基本上有三種不同的時鐘可以使用:

  • System.currentTimeMillis()
    如同掛在牆壁上的時鐘(時間/日期)以milliseconds表示之,可被使用者或經由網路透過setCurrentTimeMillis(long)隨意往前或往後調整的時鐘。此時鐘應該只用來與真實時間相關是務上,例如行事曆或鬧鐘等應用程式。
    計算時距或經過時間,應該使用底下的時鐘。

  • SystemClock.uptimeMillis()
    計算從系統啟動booted到現在所經過的milliseconds時間,但當系統進入深睡時(CPU停止,螢幕關閉,裝置等待外部輸入) 此時鐘會停止,除此之外不受其他影響。此時鐘是大部份計算時間間隔的基礎,例如Thread.sleep(millls)Object.wait(millis)System.nanoTime()。它保證是遞增的,建議用來計算一般使用者介面事件、效能或其他任何無須考慮裝置睡覺時間的時間間隔。

  • SystemClock.elapsedRealtime()
    計算從系統啟動booted到現在所經過的milliseconds時間,包括系統深睡時間。此時鐘用來必須計算橫跨多個系統睡覺時間的時間間隔。

時間顯示的部分,預設會顯示MM:SS格式的時間),如果計時破小時的話會使用H:MM:SS(時:分:秒)顯示

另外可以使用Chronometer的setOnChronometerTickListener()方法,添加一個事件監聽器
並且OverrideonChronometerTick()這個method
每一次Chronometer增加秒數時會透過這個method來更新textView的文字
所以這邊可以用來自訂你想要的邏輯或是不同的時間格式
比如說能實現每到20秒自動停止並重置或是想自訂時間顯示的格式等等功能
(請見下面範例原始碼)

範例原始碼

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="io.northbei.chronometer.MainActivity">

    <Chronometer
        android:id="@+id/timer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:textSize="40dp"
        android:countDown="false"
        android:format="00:00:00"/>

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="開始"
        android:layout_below="@+id/timer"/>

    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="停止"
        android:layout_below="@+id/start"/>

    <Button
        android:id="@+id/reset"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="重置"
        android:layout_below="@+id/stop"/>

</RelativeLayout>

MainActivity.java

package com.pontus.wishar.chronometer;

import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;

public class MainActivity extends AppCompatActivity {

    private Chronometer timer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        timer = (Chronometer) findViewById(R.id.timer);

        final Button startBtn = (Button) findViewById(R.id.start);
        final Button stopBtn = (Button) findViewById(R.id.stop);
        final Button resetBtn = (Button) findViewById(R.id.reset);

        startBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // SystemClock.elapsedRealtime()方法會回傳從開機到現在的時間(包含休眠時間)
                // 把這個時間做為一個Base,從這個Base開始計時
                timer.setBase(SystemClock.elapsedRealtime());
                timer.start();
            }
        });

        stopBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                timer.stop();
            }
        });

        resetBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                Log.d("resetBtn", "onClick: 微秒"+SystemClock.elapsedRealtime());
                timer.setBase(SystemClock.elapsedRealtime());
                timer.stop();
            }
        });

        timer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            // 每一次Chronometer增加秒數時會透過這個method更新textView的文字
            // 所以這邊可以用來自訂你想要的邏輯或是不同的時間格式
            // 比如說今天每到20秒就要自動停止然後reset,或是你想要顯示24小時制的時:分:秒
            // 就可以Override Chronometer的onChronometerTick(),在method內加上自己的邏輯之後再更新textView

            @Override
            public void onChronometerTick(Chronometer chrono) {
                //getBase是用來取得上一次setBase()的時間
                long time = SystemClock.elapsedRealtime() - chrono.getBase();
                //這裡將毫秒轉成時:分:秒
                int h   = (int)(time /3600000);
                int m = (int)(time  - h*3600000)/60000;
                int s= (int)(time  - h*3600000 - m*60000)/1000 ;
                String hh = h < 10 ? "0"+h: h+"";
                String mm = m < 10 ? "0"+m: m+"";
                String ss = s < 10 ? "0"+s: s+"";
                //最後更新文字
                chrono.setText(hh+":"+mm+":"+ss);
            }
        });
    }

}

Chronometer Demo截圖結論

基本上Chronometer只能滿足一般的使用場景,如果要實現比如精確到毫秒,或者複雜格式的計時器
就要考慮用自定義的一系列方法去實時計時,並把計時的結果不斷刷新寫入要顯示時間的元件(比如TextView )中

Reference

Chronometer | Android Developers
Android零基礎入門|日曆視圖CalendarView和定時器Chronometer
Android: 時鐘Clock機制
android Chronometer(计时器)

results matching ""

    No results matching ""