2

I'm doing this way to save the state and restore it after rotation when the chronometer is running. Android_Chronometer pause

When I stop the timer at Xsec and then after Y seconds I change the orientation the chronometer marks X+Y seconds. I'd like to leave the time of a stopped chronometer as it was before rotation, no matter how much time has passed. How should I do?

Community
  • 1
  • 1
user3290180
  • 4,260
  • 9
  • 42
  • 77

3 Answers3

3

I had a similar question about the Chronometer class and how to survive orientation changes. While there are several useful posts and examples, none that I found addressed the total question.

This was a helpful post here Android_Chronometer pause, which helped with demonstrating the need to save the elapsedTime in order to resume timing.

However, this did not discuss how to make the Chronometer survive Android life cycle orientation changes. What you do with the elapsed time is slightly different between when the timer is running vs. when it is paused.

Here is that I did to put it all together - pausing, resuming, resetting, in a nice class, and surviving orientation:

 public class ChronometerWithPause extends Chronometer {
    private long timeWhenStopped = 0;
    private boolean isRunning = false;

    private final String getTimeKey() {
        return "KEY_TIMER_TIME" + getId();
    }
    private final String getIsRunningKey() {
        return "KEY_TIMER_RUNNING" + getId();
    }

    public ChronometerWithPause(Context context) {
        super(context);
    }

    public ChronometerWithPause(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ChronometerWithPause(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void start() {
        setBase(SystemClock.elapsedRealtime() - timeWhenStopped);
        isRunning = true;
        super.start();
    }

    @Override
    public void stop() {
        isRunning = false;
        timeWhenStopped = SystemClock.elapsedRealtime() - getBase();
        super.stop();
    }

    public void reset() {
        stop();
        isRunning = false;
        setBase(SystemClock.elapsedRealtime());
        timeWhenStopped = 0;
    }

    public boolean isRunning() {
        return isRunning;
    }

    public long getCurrentTime() {
        return timeWhenStopped;
    }

    public void setCurrentTime(long time) {
        timeWhenStopped = time;
        setBase(SystemClock.elapsedRealtime() - timeWhenStopped);
    }

    public void saveInstanceState(Bundle outState) {
        if (isRunning) {
            timeWhenStopped = SystemClock.elapsedRealtime() - getBase();
        }
        outState.putLong(getTimeKey(), getCurrentTime());
        outState.putBoolean(getIsRunningKey(), isRunning());
    }

    public void restoreInstanceState(Bundle inState) {
        isRunning = inState.getBoolean(getIsRunningKey());
        setCurrentTime(inState.getLong(getTimeKey()));
        timeWhenStopped = SystemClock.elapsedRealtime() - getBase();
        if (isRunning) {
            super.start();
        }
    }
}

Note that you can use this in onSaveInstanceState() and onCreate() like this:

protected void onSaveInstanceState(Bundle outState) {
           ...
           timer.saveInstanceState(outState);
           ...

and then in onCreate you can restore the timer function with:

if (savedInstanceState != null) {
             // . . .
                timer.restoreInstanceState(savedInstanceState);
             // . . .
}
Mike
  • 515
  • 6
  • 14
0

If you are into slightly hack-y solutions, you can also do the following: Save the value of the ChronometerInstance.getText() into the Bundle and then re-set it with ChronometerInstance.setText(). It's not very friendly, but it works and does not involve calculating offsets and storing long values until you actually need them.

It completely messes with the ability to re-start the Chronometer, too, but since resuming the Chronometer behaves unexpectedly on resume anyway (continues with the same base, so it'll jump to whatever time it would've had without being stopped), that isn't too big of a loss, in my opinion.

Still, if you will ever need the old base time, go with the solution from the comments of the other solution: Save the value of

long diff = SystemClock.elapsedRealtime() - chronometerInstance.getBase();

Then, when you want to restore it, set

ChronometerInstance.setBase(SystemClick.elapsedRealtime() - diff);

If it does not display the value afterwards, you will probably have to force a re-draw. The easiest way is probably to just do a

ChronometerInstance.start();
ChronometerInstance.stop();

(as I have no idea if .invalidate() will do the trick)

malexmave
  • 1,283
  • 2
  • 17
  • 37
-1

Thanks for the clarification in the comments.

To solve your problem you can easily save in

onSaveInstanceState()

a variable related to the current status of your cronometer and then retrieve it in onCreate or in

onRestoreInstanceState()

(The second method is better) and set your cronometer status accordingly.

EDIT: To retrieve the elapsed time from the chronometer call:

SystemClock.elapsedRealtime() - chronometerInstance.getBase();
Amedeo Baragiola
  • 314
  • 4
  • 14
  • I'm doing so but how should I set the chronometer to show the same time as when it was stopped in the previous orientation? – user3290180 Feb 04 '15 at 16:40
  • You can save a long variable and save the timestamp in it – Amedeo Baragiola Feb 04 '15 at 16:41
  • I don't know how to do that, there are no timestamps http://developer.android.com/reference/android/widget/Chronometer.html – user3290180 Feb 04 '15 at 16:59
  • Okay, confirm if I've understood your problem, your problem is that you can't retrieve the elapsed time from the chronometer? If so, it is really easy: just call SystemClock.elapsedRealtime() - chronometerInstance.getBase(); – Amedeo Baragiola Feb 04 '15 at 17:03
  • if I do that I get the time of the chronometer as if it were always running, but now it's stopped so it should mark the same time as when the stop method was called. – user3290180 Feb 04 '15 at 17:05
  • Call it just after the stop method..you'll get the right time – Amedeo Baragiola Feb 04 '15 at 17:07
  • I'm just doing so, I'm saving the time as showed by the link above. My issue is to make the chronometer to mark that time X when it was stopped by stop() method. – user3290180 Feb 04 '15 at 17:14
  • can you try? just put a simple chronometer in your layout and then rotate it, you'll notice that it will mark 00:00 so you'll need to save the state and restore it as the link says. But if you stop the chronometer before you turn your device, you'll want to make it mark the same fixed time even after the rotation. – user3290180 Feb 04 '15 at 17:17
  • Okay... Make a variable called elapsedTime (a class variable) and after you call stop, save the elapsed time in the elapsedTime variable using the trick above, then when you need to save the chronometer value of screen rotation pick the value of elapsedTime...it should work – Amedeo Baragiola Feb 04 '15 at 17:19