Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ShadowCountDownTimer not work #7479

Closed
WingsII opened this issue Aug 5, 2022 · 9 comments
Closed

ShadowCountDownTimer not work #7479

WingsII opened this issue Aug 5, 2022 · 9 comments

Comments

@WingsII
Copy link

WingsII commented Aug 5, 2022

Description

If CountDownTimer is used in the code, robolectric will automatically use ShadowCountDownTimer, I found that it cannot trigger onTick() callback. And its internal data (mHandler, etc.) are empty.
image
image

If I use the original CountDownTimer object, or a custom empty Shadow object, this problem does not occur. Member variables are also normal.
image
image

Steps to Reproduce

Create a CountDownTimer in the Test case and run timer.start(), its member variables are empty, and will not trigger onTick.

Robolectric & Android Version

Robolectric : 4.2.1
JDK 1.8.0_332

Link to a public git repo demonstrating the problem:

NA

@utzcoz
Copy link
Member

utzcoz commented Aug 5, 2022

Hi @WingsII , 4.2.1 is old in a sense. Could you try latest 4.8.1 to check whether this problem was fixed? I remember there are some fixes were checked in for time. Looking forward your feedback. Thanks.

@WingsII
Copy link
Author

WingsII commented Aug 5, 2022

Hi @WingsII , 4.2.1 is old in a sense. Could you try latest 4.8.1 to check whether this problem was fixed? I remember there are some fixes were checked in for time. Looking forward your feedback. Thanks.

After testing, this problem still exists on the latest version.

Robolectric & Android Version

Robolectric : 4.8.1
JDK 11.0.11

@hoisie
Copy link
Contributor

hoisie commented Aug 5, 2022

Ah good catch. I notice that ShadowCountDownTimer's __constructor__ shadow method does not invoke the original constructor. This ruins the normal object initialization process and leaves a lot of the members uninitialized. It should have a call to Shadow.invokeConstructor.

https://github.com/robolectric/robolectric/blob/master/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCountDownTimer.java

@hoisie
Copy link
Contributor

hoisie commented Aug 5, 2022

@WingsII from the shadow API it appears thata you have to call ShadowCountDownTimer.invokeTick:

https://github.com/robolectric/robolectric/blob/master/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCountDownTimer.java#L34-L36

@hoisie
Copy link
Contributor

hoisie commented Aug 5, 2022

Looks like the real code uses SystemClock.elapsedRealtime(), which gives a virtual/fake time in Robolectric. However, it should be possible to idle the scheduler to invoke the ticks.

@WingsII
Copy link
Author

WingsII commented Aug 6, 2022

Looks like the real code uses SystemClock.elapsedRealtime(), which gives a virtual/fake time in Robolectric. However, it should be possible to idle the scheduler to invoke the ticks.

There are several points:

  1. In the real environment, CountDownTimer is a local variable and cannot be called directly.

  2. I tried to write ShadowLooper.idleMainLooper(*) but it still doesn't work actually, because the internal variable mHandler is null.

  3. According to the source code, if it is initialized correctly, CountDownTimer::onTick() will be called once when start() is used.

  4. Why doesn't ShadowCountDownTimer invoke the original constructor when it initializes. Is this a bug or is there some reason? Will it be fixed later?

@hoisie
Copy link
Contributor

hoisie commented Aug 6, 2022

Why doesn't ShadowCountDownTimer invoke the original constructor when it initializes. Is this a bug or is there some reason? Will it be fixed later?

It is because the constructor of CountDownTimer is shadowed in ShadowCountDownTimer (the __constructor__ method). I would agree that this is a bug. The __constructor__ method should call the original constructor as well.

@hoisie
Copy link
Contributor

hoisie commented Aug 6, 2022

Specifically, the constructor should probably be doing this:

  @Implementation
  protected void __constructor__(long millisInFuture, long countDownInterval) {
    this.countDownInterval = countDownInterval;
    this.millisInFuture = millisInFuture;
    this.started = false;
    // call the original constructor
    Shadow.invokeConstructor(
        CountDownTimer.class,
        countDownTimer,
        ClassParameter.from(long.class, millisInFuture),
        ClassParameter.from(long.class, countDownInterval));
  }

@WingsII
Copy link
Author

WingsII commented Aug 6, 2022

Specifically, the constructor should probably be doing this:

  @Implementation
  protected void __constructor__(long millisInFuture, long countDownInterval) {
    this.countDownInterval = countDownInterval;
    this.millisInFuture = millisInFuture;
    this.started = false;
    // call the original constructor
    Shadow.invokeConstructor(
        CountDownTimer.class,
        countDownTimer,
        ClassParameter.from(long.class, millisInFuture),
        ClassParameter.from(long.class, countDownInterval));
  }

It works, great!

@WingsII WingsII closed this as completed Aug 6, 2022
copybara-service bot pushed a commit that referenced this issue Aug 8, 2022
This allows CountDownTimer's internal members to be properly initialized.

At some point it may be worth investigating if we can remove
ShadowCountDownTimer altogether.

Fixes #7479

PiperOrigin-RevId: 465712347
copybara-service bot pushed a commit that referenced this issue Aug 8, 2022
This allows CountDownTimer's internal members to be properly initialized.

At some point it may be worth investigating if we can remove
ShadowCountDownTimer altogether.

Fixes #7479

PiperOrigin-RevId: 466084183
hoisie added a commit that referenced this issue Aug 22, 2022
This allows CountDownTimer's internal members to be properly initialized.

At some point it may be worth investigating if we can remove
ShadowCountDownTimer altogether.

Fixes #7479

PiperOrigin-RevId: 466084183
hellosagar pushed a commit to hellosagar/robolectric that referenced this issue Sep 3, 2022
This allows CountDownTimer's internal members to be properly initialized.

At some point it may be worth investigating if we can remove
ShadowCountDownTimer altogether.

Fixes robolectric#7479

PiperOrigin-RevId: 466084183
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants