App instantiated twice on startup

Hi,

My app implements a background task, glance and widget.

When the simulator starts in glance mode, my AppBase derivation is initiated twice. The first is stopped immediately, the second than persists.

Here is the log of the function calls. I don't use onStart, and I have also excluded the entries made by the background instance:

29.3.2025 10:13:12: EvccApp: initialize
29.3.2025 10:13:12: EvccApp: getGlanceView
29.3.2025 10:13:12: EvccApp: onStop
29.3.2025 10:13:13: EvccApp: initialize
29.3.2025 10:13:13: EvccApp: getGlanceView

What could be the reason for the class to be instantiated twice? Is this a simulator thing?

This only happens for the glance. When I change the Glance Launch Mode in the simulator to start right into the widget, the class is instantiated only once.

  • Seems like a bug, unless someone can give a logical explanation why this behavior would be necessary and desirable.

    idk, sounds like a pretty strong demand directed at people (general forum users) who don't work for Garmin (or you).

    Every time you see something you don't like in CIQ, you go around demanding explanations as if the forum owes them to you.

    Why not just file a bug report and see what Garmin says, if you care that much?

    This doesn't happen with a watchface. This happens on both an FR235 (CIQ 1) and F7X (CIQ 5).

    The fact that the same behaviour has apparently persisted for 10 years and only for certain app types, seems to indicate that it's by design. (Perhaps there's a reason we're not privy to, or perhaps it's one of those arguably bad design decisions that nonetheless won't be reversed.) Then again it could be a bug that they haven't caught in all these years (that's not *too* crazy, knowing Garmin).

    However, if it is a bug, people have apparently been writing apps for 10 years without being adversely affected, otherwise it would've been fixed by now. Maybe most people aren't writing code that depends on onUpdate() being called a certain number of times?

  • I also think it's a bad idea to assume that onUpdate() will be called twice, because then your code will break if it's only called once.

    It's never not called just once, but yeah it would be a problem in the unlikely event that Garmin ever fixes it. The other problem I didn't point out in my previous post is that the third call to onUpdate is much less than the 1000 ms timer. Even if I set the timer to 3000 ms or more this behavior is the same. This is why I do not set the timer on the first call, it would be executed right away to call requestUpdate, which would already be executing which is where I would consistently see crashes. Yes, I don't disagree that it's a non-ideal solution, but it is the one that works.

    At least you are able to replicate the double call behavior per your code comment and screenshot so thanks for that. The difference in your test is that onUpdate doesn't do anything that takes a substantial amount of time like call drawing functions in another class, so it may be have something to do with the differences in observed behavior. This is also why my first call to onUpdate is basically a no-op. 

    The other thing I do is I set a repeating timer. There is a little time interval creep with a non-repeating timer, the repeating timer is more consistent..

  • This code is not written well. It does other things in onUpdate than updating the screen. And it also assumes things about onUpdate being called magically. And it also abuses the timer: instead of setting a repeating timer it sets a one-off timer, then another, another, ...

    All the above things together cause it to behave strangely.

    Instead I would set a repeating timer in onShow, stop it in onHide. This will ensure that once the system "calmed down" onUpdate will be called in the right intervals and not too many times.

    There is no "contract" that onUpdate is only called when you request it. There is a contract that after requesting it, onUpdate will shortly be called.

    Another more complicated way could be to measure the time either since the last time onUpdate was called or the time spent in onUpdate (in case it does very different things between different calls) and do the manual one-off timer based on the measurement: set it to timerInterval-timeSpent. This would smooth out an animation.