Android Chronometer Tutorial

View more Tutorials:

1- Android Chronometer

In  Android, Chronometer is an interface component that simulates a simple timer.
Note: The  Chronometer component is not available in the  Palette of the design window, so you need to use the following XML code to add it into the interface.
<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="false"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="true"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

android:countDown

This attribute specifies that this Chronometer counts down or counts up with its value of  true/false respectively.
<!-- Counts Up -->
<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="false"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

<!-- Counts Down -->
<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="true"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

android:format

This attribute specifies a time format string for Chronometer.
By default, Chronometer displays time in the format of "MM:SS" when the time is less than 1 hour, or "H:MM:SS" if the time is more than 1 hour. The value of the  android:format attribute must be in form of  "Text1 %s Text2", and when Chronometer shows the time, you will get a string with the format of "Text1 MM:SS Text2" or  "Text1 H:MM:SS Text2".

2- Chronometer Methods

Chronometer Methods
long getBase()

void setBase(long base)

String getFormat()

void setFormat(String format)

boolean isCountDown()

void setCountDown(boolean countDown)

boolean isTheFinalCountDown()

void start()

void stop()

setBase(long base)

This method is only useful for the count up  Chronometer, which is used to set the time that Chronometer is in reference to (corresponding to the value of 00:00).
The  base parameter is the number of milliseconds since the system was started which includes the device sleep time. If you are using an  Android Emulator, the time when the computer starts will be deemed as the origin of the coordinates.
// Returns milliseconds since system boot, including time spent in sleep.
long elapsedRealtime = SystemClock.elapsedRealtime();

// Set the time that the count-up timer is in reference to.
this.chronometer.setBase(elapsedRealtime);

this.chronometer.start();

setFormat(String format)

By default, Chronometer displays time in the format of "MM:SS" when the time is less than 1 hour, or "H:MM:SS" if the time is more than 1 hour. The value of the format attribute must be in form of  "Text1 %s Text2" so that when Chronometer shows the time, you will get a string with the format of "Text1 MM:SS Text2" or  "Text1 H:MM:SS Text2".
If you want a deeper customization of the  Chronometer time display format, you should check out the example at the end of this article.

3- Chronometer Events

  • TODO

4- Example: Chronometer (Count up)

Let's get started with a simple count up  Chronometer which can be used to measure the time for running of an athlete.
OK, Now on  Android Studio, create a project:
  • File > New > New Project > Empty Activity
    • Name: ChronometerExample
    • Package name: org.o7planning.chronometerexample
    • Language: Java
Here is the example interface:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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=".MainActivity">


    <TextView
        android:id="@+id/textView_info"
        android:layout_width="378dp"
        android:layout_height="24dp"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:gravity="center_horizontal"
        android:text="(Info)"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Chronometer
        android:id="@+id/chronometerExample"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_weight="1"
        android:gravity="center_horizontal"
        android:textSize="60sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_info" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chronometerExample">

        <Button
            android:id="@+id/button_start"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            android:layout_weight="1"
            android:text="Start"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/button_stop"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            android:layout_weight="1"
            android:text="Stop"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/button_resetBaseTime"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            android:layout_weight="1"
            android:text="Reset"
            android:textAllCaps="false" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.chronometerexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.TextView;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    private TextView textViewInfo;
    private Chronometer chronometer;
    private Button buttonStart;
    private Button buttonStop;
    private Button buttonResetBaseTime;

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

        this.textViewInfo = (TextView) findViewById(R.id.textView_info);
        this.chronometer = (Chronometer)findViewById(R.id.chronometerExample);

        this.buttonStart = (Button)findViewById(R.id.button_start);
        this.buttonStop = (Button)findViewById(R.id.button_stop);
        this.buttonResetBaseTime = (Button)findViewById(R.id.button_resetBaseTime);

        this.buttonStop.setEnabled(false);
        this.buttonResetBaseTime.setEnabled(false);

        this.buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStart();
            }
        });

        this.buttonStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStop();
            }
        });


        this.buttonResetBaseTime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doResetBaseTime();
            }
        });
    }

    // @totalMilliseconds: milliseconds since system boot, including time spent in sleep.
    private void showInfo(long totalMilliseconds)  {
        // Seconds
        long totalSecs = totalMilliseconds / 1000;
        // Show Info
        long hours = totalSecs / 3600;
        long minutes = (totalSecs % 3600) / 60;
        long seconds = totalSecs % 60;

        this.textViewInfo.setText("Base Time: " + totalSecs +" ~ " + hours + " hours " + minutes+" minutes " + seconds + " seconds");
    }

    private void doStart()  {
        // Returns milliseconds since system boot, including time spent in sleep.
        long elapsedRealtime = SystemClock.elapsedRealtime();
        // Set the time that the count-up timer is in reference to.
        this.chronometer.setBase(elapsedRealtime);
        this.chronometer.start();
        this.showInfo(elapsedRealtime);
        //
        this.buttonStart.setEnabled(false);
        this.buttonStop.setEnabled(true);
        this.buttonResetBaseTime.setEnabled(true);
    }

    private void doStop()  {
        this.chronometer.stop();
        //
        this.buttonStart.setEnabled(true);
        this.buttonStop.setEnabled(false);
        this.buttonResetBaseTime.setEnabled(false);
    }

    private void doResetBaseTime()  {
        // Returns milliseconds since system boot, including time spent in sleep.
        long elapsedRealtime = SystemClock.elapsedRealtime();
        // Set the time that the count-up timer is in reference to.
        this.chronometer.setBase(elapsedRealtime);
        this.showInfo(elapsedRealtime);
    }

}

5- Example: Chronometer (Count down)

An example of a count down  Chronometer.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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=".MainActivity">


    <TextView
        android:id="@+id/textView_1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginRight="16dp"
        android:background="#D7F3C9"
        android:gravity="center_horizontal"
        android:text="Count Down Chronometer"
        app:layout_constraintHorizontal_bias="0.047"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Chronometer
        android:id="@+id/chronometerCountDown"
        android:countDown="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_weight="1"
        android:gravity="center_horizontal"
        android:textSize="60sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_1" />

    <Button
        android:id="@+id/button_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Start"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chronometerCountDown" />


</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.chronometerexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;

public class MainActivity extends AppCompatActivity {

    private Button buttonStart;
    private Chronometer chronometerCountDown;

    private int counter = 10;

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

        this.chronometerCountDown = (Chronometer) findViewById(R.id.chronometerCountDown);
        this.buttonStart = (Button) findViewById(R.id.button_start);

        this.chronometerCountDown.setText(counter + "");

        this.buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStart();
            }
        });

        // This listener will customize the chronometer text content.
        // It will show number from 10 to 0 repeatedly.
        this.chronometerCountDown.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                onChronometerTickHandler();
            }
        });
    }


    private void onChronometerTickHandler()  {
        if(this.counter < 0) {
            this.counter = 10;
        }
        this.chronometerCountDown.setText(counter + "");
        this.counter--;
    }


    private void doStart()  {
        this.chronometerCountDown.start();
    }

}

6- Example: Custom Format

The example below allows you to customize the text shown on​​​​​​​ Chronometer:
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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=".MainActivity">


    <TextView
        android:id="@+id/textView_2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginRight="16dp"
        android:background="#D7F3C9"
        android:gravity="center_horizontal"
        android:text="Custom Format"
        app:layout_constraintHorizontal_bias="0.047"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Chronometer
        android:id="@+id/chronometer_customFormat"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_weight="1"
        android:gravity="center_horizontal"
        android:textSize="30sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_2" />

    <Button
        android:id="@+id/button_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Start"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chronometer_customFormat" />


</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.chronometerexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;

public class MainActivity extends AppCompatActivity {

    private Button buttonStart;
    private Chronometer chronometerCustomFormat;

    private int counter = 10;

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

        this.chronometerCustomFormat = (Chronometer) findViewById(R.id.chronometer_customFormat);
        this.chronometerCustomFormat.setText("Please click start!");
        this.buttonStart = (Button) findViewById(R.id.button_start);


        this.buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStart();
            }
        });


        this.chronometerCustomFormat.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                onChronometerTickHandler();
            }
        });
    }


    private void onChronometerTickHandler()  {
        long delta = SystemClock.elapsedRealtime() - this.chronometerCustomFormat.getBase();

        int h = (int) ((delta / 1000) / 3600);
        int m = (int) (((delta / 1000) / 60) % 60);
        int s = (int) ((delta / 1000) % 60);

        String customText = h +" hours " + m +" minutes " + s +" seconds";

        this.chronometerCustomFormat.setText(customText);
    }


    private void doStart()  {
        long base = SystemClock.elapsedRealtime();
        this.chronometerCustomFormat.setBase(base);
        this.chronometerCustomFormat.start();
    }

}

View more Tutorials: