Android Chronometer Timer

Hi, in this tutorial I will show you and I will try to explain how to introduce timer in your app, how to pause it and how to resume it.

First you need to know that we will have to use the Chronometer class which is after all a TextView. Yes, that’s true, Chronometer class is a direct subclass of TextView.  So, long story short, this is the class which will help us to add a timer to our app. Let’s start coding 😀

1.  Create a new project and name your activity MainActivity (it should already be named this way when the project is created);

2. Now, go to res – layout  and you will have to see an xml called activity_main.xml. If you don’t use Android Studio you might see a different name and for the purpose of this tutorial you should rename it to “activity_main.xml”. Here you should add the following code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/button_start"
            android:text="Start"/>

    <Button android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button_resume"
        android:text="Resume"/>
</LinearLayout>

We created a view with 2 buttons: Start and Resume.

3.  Now, before creating the second activity we have to do some additional steps.  So, create a new Java class and name it ApplicationContextProvider and follow the steps from this tutorial.

4.  Now create a new Java class and name it SharedPreferenceManager. This class will be used to persist the elapsed time. Add the following code:

package com.example.chronometer;

import android.content.Context;
import android.content.SharedPreferences;

/**
 * Manager (singleton) for SharedPreference operations
 */
public class SharedPreferenceManager {
    public static final String TIME_SPENT_ON_LEVEL = "time.spent.on.level";
    private static SharedPreferenceManager sInstance;

    /**
     * Used to make commits to the shared preferences file, don't use this directly, use the getter!!
     */
    private SharedPreferences mPreferencesManager;

    /**
     * Private Constructor
     */
    private SharedPreferenceManager() {

    }

    /**
     * Gets the instance(object) for this class
     *
     * @return The Instance of SharedManager singleton class
     */
    public static SharedPreferenceManager instance() {
        if (sInstance == null) {
            sInstance = new SharedPreferenceManager();
        }

        return sInstance;
    }

    public SharedPreferences getPreferencesManager() {

        if (mPreferencesManager == null) {
            mPreferencesManager = ApplicationContextProvider.getContext().getSharedPreferences("saveState", Context.MODE_PRIVATE);
        }

        return mPreferencesManager;
    }

    /**
     * Save the time spent on a level
     *
     * @param milliseconds time spent on a level
     */
    public void persistTimeSpentOnLevel(long milliseconds) {

        getPreferencesManager().edit().putLong(TIME_SPENT_ON_LEVEL, milliseconds).commit();

    }
    /**
     * Returns the time spent on a level or 0 if the game is new
     *
     * @return milliseconds passed since the game started
     */
    public long getTimeSpentOnLevel() {

        return getPreferencesManager().getLong(TIME_SPENT_ON_LEVEL, 0);

    }
}

5. Now we have to create the 2nd activity. Name it TimerActivity and add the following code:

package com.example.chronometer;

import android.app.Activity;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.Chronometer;


public class TimerActivity extends Activity {

    private Chronometer mChronometer;


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

        mChronometer = (Chronometer)findViewById(R.id.chronometer);
    }

    @Override
    protected void onResume() {
        super.onResume();

        mChronometer.setBase(SystemClock.elapsedRealtime() + SharedPreferenceManager.instance().getTimeSpentOnLevel());
        mChronometer.start();
    }

    @Override
    protected void onPause() {
        super.onPause();

        long timeWhenStopped = mChronometer.getBase() - SystemClock.elapsedRealtime();
        SharedPreferenceManager.instance().persistTimeSpentOnLevel(timeWhenStopped);
        mChronometer.stop();
    }
}

6. Go to res – layout and name your newly created activity_timer.xml and add the following code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.chronometer.TimerActivity"
    android:orientation="vertical">

    <Chronometer
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/chronometer"/>

</LinearLayout>

7. And the last step is to add the following code to the MainActivity class:

package com.example.chronometer;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

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

        Button startButton = (Button)findViewById(R.id.button_start);
        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // reset the timer
                SharedPreferenceManager.instance().persistTimeSpentOnLevel(0);

                // start the Timer activity
                Intent intent = new Intent(MainActivity.this, TimerActivity.class);
                startActivity(intent);
            }
        });

        Button resumeButton = (Button)findViewById(R.id.button_resume);
        resumeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // start the Timer activity
                Intent intent = new Intent(MainActivity.this, TimerActivity.class);
                startActivity(intent);
            }
        });
    }
}

Maybe you wonder what is SystemClock.elapsedRealtime(); Well, this returns the time in milliseconds since your device booted included sleep time. This means that if you test your app on an emulator and the emulator opened 30 minutes ago, this method will return 1800 000 milliseconds (=30 min).

Also setBase() has this definition: set the time that the count-up timer is in reference to.

If we look inside the Chronometer class, the setBase() method uses SystemClock.elapsedRealtime(); when the text must be updated with the correct time and at some point they subtract this time from a variable that was initialized with SystemClock.elapsedRealtime(); So this means that if you want to start your count from 00:00 you have to set the base like this:

mChronometer.setBase(SystemClock.elapsedRealtime());

And I think that’s it. The final result is:

keyboard_arrow_up