Storage.setValue doesn't seem to be persistent on WatchFace?

I think more than likely I have a bug in my code, but I still want to check if maybe this is intended behavior? I tried to setValue and getValue to persist some data when I leave the WatchFace screen (such as when navigating to glances or other apps), but it only seems to be returning null and reverting to my fallback value.

function loadValue(key as String, fallbackValue as Lang.Object or Null) {
    var value = Storage.getValue(key);
    if (value == null) {
        return fallbackValue;
    }
    return value;
}

...

function onHide() as Void {
    ...
    Storage.setValue("batteryInDays", batteryInDays);
}

function onShow() as Void {
    ...
    batteryInDays = loadValue("batteryInDays", stats.batteryInDays);
}

The reason why I don't just want to use batteryInDays from the system stats is that it's only accurate with 1 digit of precision. For example, my custom implementation will calculate the battery drain and return 7.5 days but the batteryInDays field will return 7.0

  • i use onStop for my fenix7 watchface and it seems to work fine

    Sorry for jumping in.

    According to the docs, onStop should be called, when the app is unloaded from memory, but from what I see, WF is running while you are viewing glances or navigating other system menus, so onStop isn't called, I guess.

    I have a kind of similar problem, as I need to catch "watchface goes off the screen" event and change a variable value. I asked MobileDriveway (the developer of one of the most popular watchfaces) about it:

    Hi, would you be so kind to reveal some technical details about switching to second screen functionality?

    I'm trying to implement the same in my own watchface. I store timestamp in onEnterSleep() and compare it with the current timestamp in onExitSleep() and do the switching, if the duration is short. This works fine except for one thing: whenever I exit to complication and return back to watchface or go to system glances loop and return back quickly enough, my WF switches to another screen, as onEnterSleep()/onExitSleep() is called when my WF goes off the screen and shows again. I tried to nullify timestamp in onHide() to avoid that, but it doesn't work, as onHide() doesn't seem to be called.

    Could you, please, tell, how do you overcome this?

    They answered, there's no workaround.

    So, my question to you is the following: what exactly do you do in onStop (change variable, save to storage, ...), and are you 100% sure it is working, when you go to glances and return to the watchface?

  • I added some println  calls to one of my basic watch faces, and sideloaded it to a 965.  Created the log file....

    I do a println in onStart, in onStop. showing the value I want to save to storage with setValue. and then in initialize for the view where I do a getValue.

    here's the results

    got=null
    onStop 4:41
    onStart
    got=4:41
    onStop 4:46
    onStart
    got=4:46
    onStop 4:46

    the first "got=" is a null, as I didn't have the value in storage yet.

    You then see the onStop where it's saved (moving to the glance loop), the next onStart and "got=" shows what was saved in onStop, then a couple more times I left the watch face and came back..

    You can see onStop is being called as it should,

  • OK, thanks for the info, I'll try later the same in my WF, when I have possibility. Could you, please, also store the same value to a variable and print it along with the value from storage?

    If I understand documentation correctly, with onStop it is possible to save app state to storage, and load it later in onStart. I don't do this (as I don't want to save timestamp of entering to sleep mode in storage, because it is called too often, and there's no point to persist it at all), yet see, that private variable in my view retains its value after returning back to WF, so either onStop is called without unloading app and releasing all its used memory, or your device/firmware works differently, than mine (Fenix 7X, latest stable 17.28).

  • The value I'm saving is the last time from when onUpdate ran.

    If you have a background service in your WF, understand that onStart and onStop may be called more often than you expect.  Even if you just have the background permission set but no background service.

    It could be there is a bug on the f7x.  Try what I did, and report it if that's the case.

  • If you have a background service

    I don't have Background permission and don't use background service.

    The value I'm saving is the last time from when onUpdate ran.

    It looks I was not clear enough. I wanted to know, will your device keep global or class variable after onStop/onStart or not. You store time in onUpdate to variable, then in onStop save this variable's value to storage, then read this value from storage in onStart. I wanted to know, will your "var lastOnUpdateCallTime" keep its value or not after onStop/onStart.

    Anyway, I'll try using onStop later to nullify my variable with timestamp. Thank you.

  • I don't do the getValue in onStart, but in initialize for the view.  and after onStop is called, the watch face is "done" and it starts clean the next time it runs.  That's why you use Storage - to preserve the value between runs.

    As a test, have you tried doing the setValue() when what you want to save changed?  Say in onUpdate.  That's kind of typical how I actually use Storage.  If it's data from a background service, I'll do it in onBackground data So every 5 minutes at most..

  • I don't do the getValue in onStart, but in initialize for the view.  and after onStop is called, the watch face is "done" and it starts clean the next time it runs.

    OK, I think getValue in onStart and in view's initialize should give the same result, if there's no backgrounding involved.

    have you tried doing the setValue() when what you want to save changed?

    Yes, I use storage to save things "forever", when it's needed, like when changing user preferences in WF on-device settings menu. The timestamp of entering sleep mode is not the value I want to save "forever". In fact, I want it to be reset every time operating system displays something else, than my WF, but my WF keeps class variable value regardless of my desire. According to my own experience and to the message of other developer in this thread, onHide is not called for watch faces. I'll try onStop instead for resetting variable value explicitly, although it should be purged with all the other objects and variables after onStop (if onStop is ever called on my device, when viewing glances, and as I see, that variable value isn't cleared, onStop isn't called).

  • I'll try onStop instead for resetting variable value explicitly, although it should be purged with all the other objects and variables after onStop

    I tried, and it doesn't work, just as I expected. I see, that variable in view keeps its value (timestamp from onEnterSleep), so onStop isn't called, at least for my WF and on my device and firmware.

    It looks like MobileDriveway is right, and it's not possible to avoid onEnterSleep/onExitSleep calls (or to undo results of actions from these functions' bodies) while entering/exiting glances loop.

  • I've been tweaking my watch face and debugging it for the past few weeks. Only saw onHide get triggered a few times and not even sure how. Not consistent with my daily patterns (using apps or sleeping), so I got no idea what the purpose is for