0

I was learning the Lifecycle Aware Components from the Codelab which starts from Chronometer example. In step 2 I have a doubt. These are the code files for reference

ChronoActivity2.java

package com.example.android.lifecycles.step2;

import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.widget.Chronometer;
import com.example.android.codelabs.lifecycle.R;

public class ChronoActivity2 extends AppCompatActivity {

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

        // The ViewModelStore provides a new ViewModel or one previously created.
        ChronometerViewModel chronometerViewModel
                = ViewModelProviders.of(this).get(ChronometerViewModel.class);

        // Get the chronometer reference
        Chronometer chronometer = findViewById(R.id.chronometer);

        if (chronometerViewModel.getStartTime() == null) {
            // If the start date is not defined, it's a new ViewModel so set it.
            long startTime = SystemClock.elapsedRealtime();
            chronometerViewModel.setStartTime(startTime);
            chronometer.setBase(startTime);
        } else {
            // Otherwise the ViewModel has been retained, set the chronometer's base to the original
            // starting time.
            chronometer.setBase(chronometerViewModel.getStartTime());
        }

        chronometer.start();
    }
}

ChronometerViewModel.java

package com.example.android.lifecycles.step2;
import android.support.annotation.Nullable;
import android.arch.lifecycle.ViewModel;

/**
 * A ViewModel used for the {@link ChronoActivity2}.
 */
public class ChronometerViewModel extends ViewModel {

    @Nullable
    private Long mStartTime;

    @Nullable
    public Long getStartTime() {
        return mStartTime;
    }

    public void setStartTime(final long startTime) {
        this.mStartTime = startTime;
    }
}

In the above code, we are calling the setTime() only once and only when the ViewModel is being created for the very first time, that is when you start the application after a complete close. And only setTime() method should update the Long variable mStartTime. and at the end of activity File, we are calling the start() method which should start the counting of the Chronometer.

Doubt:

If we are calling the set Method only once during the Life of the app and not Activity, how does the value of the Long variable mStartTime is being updated as we can see from the else part, were we are setting the base of the Chronometer as the variable. The value that the start() is returning is no way related to the variable, so how the setTime() function is being called again and again every second.

Nishant Garg
  • 135
  • 9

2 Answers2

0

If we are calling the set Method only once during the Life of the app and not Activity

ViewModel survive in configuration changes. ViewModel depends on Activity not App Lifecycle. When your Activity destroyed (without Configuration changes) your ViewModel will be also destroyed. For your case there is no guarantee that you are calling setStartTime method only once in App Lifecycle.

how does the value of the Long variable mStartTime is being updated

Here if your ViewModel is still alive then you are getting the previous basetime by chronometerViewModel.getStartTime() by this method and setting chronometer base time.

how the setTime() function is being called again and again every second

Chronometer automatically update display time in every second. You don't have to call setTime() every second. Chronometer take care of its update itself. You have to just set a base time where he should start.

Finally if your Activity destroyed for configuration changes your ViewModle will still holds the previous data and you can use that so that you don't need recreate that data again.

Abu Yousuf
  • 5,729
  • 3
  • 31
  • 50
  • Thank you for the response, but just for curiosity, I tried deleting the start() method. Now the UI is not changing on same config. But when rotation occurs the UI gets updated. is `SystemClock.elapsedRealtime();` is actually being called again and again? – Nishant Garg Jul 08 '18 at 03:33
  • If you don't call `start()` `Chronometer` will not start counting. `Chronometer` is just a simple timer who automatically update its display text. – Abu Yousuf Jul 08 '18 at 03:37
  • UI gets updated after rotation change because you are setting base time and `setBase()` method actually update the displayed text. check source code here https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/widget/Chronometer.java and `SystemClock.elapsedRealtime();` will not called again and again because on rotation change your `ViewModle` is not null and `chronometerViewModel.getStartTime() ` is alos not null – Abu Yousuf Jul 08 '18 at 03:47
  • Welcome, Happy to help you. – Abu Yousuf Jul 08 '18 at 04:40
0

Your Doubt regarding the persistence is answered here!

Check this official code lab link and on step 2 read what's at bottom of page

- View model is linked to Activity/Fragment lifecycle only! - It's not meant for long term persistence

Your Doubt regarding whether the <code>SystemClock.elapsedRealtime()</code> is called again and again is answered here

  • The base time is just a reference from which the chronometer has to count which needs to be set once
  • SystemClock.elapsedRealtime() has to be called once and chronometer handles counting from that base time when you call start()

Hope this clears your doubt you can check official google docs here to check how chronometer works.

Nishant Dubey
  • 2,802
  • 1
  • 13
  • 18
  • I just read that one. But I just had doubt that how the timer value was being stored in the Long variable and being update after rotation – Nishant Garg Jul 08 '18 at 05:08