Simulator: can't push settings to data field

Windows 10
SDK: CIQ 3.0.7
Complete source code available upon request (*)

This is a problem that I've been wrestling with on multiple data field projects for a while now.

Sometimes when I send settings to a data field in the simulator and re-run the data field (because I don't handle onSettingsChanged), not only do the settings not get applied, but they also get reset to default.

This only happens in the simulator, not IRL.

EDIT: Now I have seen this happen IRL, with the same app (store version). I updated the app with two new booleans, and after I pushed settings, they were reset to default.
https://apps.garmin.com/en-US/apps/7...b-e97269c3cdb9

Sometimes there is a workaround where I can kill the app before sending settings, and it will work. Other times it seems like there is nothing I can do to push settings.

In the latter case I resort to hardcoding test settings in the properties XML, running the app and selecting "Reset App Data".

This is pretty frustrating and annoying, because my apps tend to have lots of settings <_< and I like testing them by changing them in the same way that the user would.

App notes:
- For compatibility across all watches, new and old, I am using Application.getApp().getProperty() to get settings
- I tend to have different settings for different targets (e.g. CIQ1 vs. CIQ2), in order to max out the capabilities of each platform
- I tend not to handle onSettingsChanged() (terrible practice, I know), because of the slight extra hit it might take in code that has to be smart enough to reinitialize certain things at run-time. In my defense, I've seen very popular apps that don't/can't handle onSettingsChanged(), and it's only really good for cosmetic changes anyway. If a metric type is changed in the middle of an activity, it may be literally impossible for the app to display that metric properly, since some metrics need to be calculated from the start.

(*) This has happened to me with so many apps, but I don't have a simple test case, I'm afraid. I do have complete source code for an app ("Lap+") where this has happened. It's source-controlled, so I'll be able to give you a usable copy of this at any time.

I wonder if having the different settings per-target "family" has something to do with it. However, I tried a very small test case and it doesn't to be that.

So maybe it's just having a large number of settings that's the problem.

Recreation procedure:

A)
-
Open "Lap+" data field project in Eclipse. Complete source code available on request.
- Run app for FR935 in the simulator
- Open app settings
- Change "theme color" to dark green. (This is the easiest setting to change where you can see it didn't work.)
- Send settings to simulator
- Run app again.
- The actual theme color will be unchanged.

B)
-
While app is still running, open app settings
- Kill the app (without closing the app settings or the simulator)
- Change the theme color to dark green
- Send settings to simulator
- Run app again
- The actual theme color will be changed to dark green

C)
- Now that the theme color has been changed, repeat A), except try to change the colour to dark blue (or anything but dark red, the default).
- The selected theme color will not be applied. As a matter of fact, when you run the app again, the theme color will be reset to the default (dark red).
  • I can't reproduce using a simple testcase. We'll need that sample code.

    From the Bug Reports Forum Rules...

    Once thread is created please send an email to [EMAIL="[email protected]"][email protected][/EMAIL] including a link to your new thread and the code sample to reproduce
  • Travis.ConnectIQ I've sent the code as requested. Try not to cry when you look at the awful, unmaintainable code >_>.
  • Former Member
    Former Member
    I've updated your ticket with some new content. Hopefully we'll have the chance to look at this soon.
  • Coleman.ConnectIQ Thanks for the update! I will say, anecdotally, that I'm still seeing the issue with various apps. Usually the workaround of killing the app before sending settings works fine.
  • @Coleman.ConnectIQ FYI, now I have a user (1 star review) complaining IRL about this problem (being unable to save modified settings) for a clone of "Lap+":
    https://apps.garmin.com/en-US/apps/d...b-0e5591be418e

    I use the "original" Lap+ data field on a 935 and I don't see the problem, although I'm fairly sure I'll see it again if I try in the simulator (without using the workaround posted above).
  • I plan to look at this further this weekend, but at first glance It does look like you are too close to the memory limits and the app settings cannot be saved. If you fake more available memory by setting the memory_limit for datafield for the fr935 in devices.xml to a larger value, the problem vanishes.

    It is quite possible that we will be able to reduce the memory load so that this works for your app, but we may not be able to avoid it completely.

  • Sounds like a memory issue to me too, as if the app is running when you change settings, those new settings are actually exchanged for the settings that are currently in memory for the running app. That's why killing the app in the sim before saving settings is a "work-around". If the app is running, you will likely see an increase in peak emory

    Not having onSettingsChanged() makes little to no difference, as that's just a way for an app to see that the settings in memory have changed - not having it doesn't prevent it from happening. If an app reads the settings each time in onUpdate() without onSettingsChanged() being used, the new settings are there. Settings aren't loaded into memory by key when one is needed - they are loaded as a whole and consistent with what's in the .set file for a running app.

    If you are tight on memory and this occurs, freeing up some memory would help, but you could be right back in this state if you add a bit more code/data, etc. As Travis said, no way to avoid it completely. Should the app get an "out of memory" and show a IQ! in this case? I think that could be worse, but maybe something like a warning from the sim should be displayed. "Unable to save settings due to memory" or something
  • Travis.ConnectIQ thanks for continuing to look at this. Appreciate it!

    jim_m_58 thanks for the feedback. Yes, memory issues would make sense in the case of the simulator, where it isn't possible to send settings unless the simulator is running (hence the work around to kill the app before sending settings).

    TL;DR In the sim and on the real device, if settings can be applied while an app isn't running (*), then it would be nice if settings could also be applied while an app is running, even if that app crashes due to running out of memory (**).

    (*) And if they can't, why not?

    (**) The only thing I can think of is that it's an intentional fail-safe which resets all the app settings to default to avoid the case where a hypothetical "bad setting" causes the app to crash. In that case, perhaps the fail-safe needs to be able to distinguish between the app running out of memory due to the settings change itself, and the app crashing for some other reason. I get that it's probably not possible though....

    ---

    How about the real-life case where a user has reported that settings can't be saved?
    1) The app doesn't need to be running for settings to be changed and saved. In this case it is a data field app, but I think this applies to any other app as well. If the app isn't running, I don't see any reason for the settings changes to fail.
    2) Even if the app is running, if pushing the settings causes it to crash (followed by restart?), I don't see any reason in principle why the settings changes can't apply to the next invocation of the app/data field. (See point 1).

    If there is indeed a difference in behaviour when pushing settings when the app is running versus not running, then I feel this is a little user-unfriendly. I get if the app crash in unavoidable (although I don't like it), but it would be nice if the settings change was guaranteed, since I feel like it would be in 1).

    By the same token, if the app running in the sim has to crash when settings are pushed, then it would be nice if the settings changes applied to the next invocation of the app.

    Is it just the case where I need to tell users to exit the app before changing settings? As I mentioned before, I have never seen any of my data fields crash in real life on settings change. I tried a few times with Garmin Connect (iOS) and my 935, but it never happened. Some of the same data fields consistently crash in the sim though (also 935) when settings are changed (without killing the app first). I don't have a CIQ 1 device like 235 to test with anymore, so I wouldn't know if those crash in real life under the same scenario.

    Not having onSettingsChanged() makes little to no difference, as that's just a way for an app to see that the settings in memory have changed - not having it doesn't prevent it from happening.


    Thanks, I get that. That's why I suggested once that it would be nice if an app could somehow opt out of run-time settings changes, to avoid memory issues. There's a whole class of settings where it's impossible (or infeasible) for settings to take effect at run-time. I don't want to go into a huge amount of detail, since I've mentioned this stuff before, but something as simple as a customizable sub-field that represents "Lap Count" or "Lap Average Pace" won't work if you apply it in the middle of an activity. Something more complex like a math formula which determines the value displayed by the datafield is pretty much impossible to apply at run-time, without writing a bunch of code that would waste a lot of memory for most watches.

    Another example is a "race predictor" -- even the Garmin race predictor setting can't be applied after the activity starts.

    I have seen popular data field apps (150k+ downloads) which also don't accept settings changes at run time....

    (I do have a widget and a device app which have run-time settings, but in that case, settings are implemented with a built-in menu.)

    My point is that (as I mentioned before), I feel like the memory limit for data fields is very small, especially on CIQ1 devices and even "modern" devices like 935, and I really wish we didn't have to keep an indeterminate amount of memory free just make sure data fields don't crash when settings are changed. If we can't or don't wish to have any settings that can be applied at run-time, then that memory is just going to waste.
  • The only thing I can think of is that it's an intentional fail-safe which resets all the app settings to default...

    That is exactly what this code is doing. Instead of taking down the app, we choose to ignore the settings file and use the defaults.

    If the app isn't running, I don't see any reason for the settings changes to fail.

    It isn't the saving of the settings file that is the problem. It is loading the settings that is the issue.

    I don't see any reason in principle why the settings changes can't apply to the next invocation of the app/data field.

    The settings are loaded immediately if the app is running, otherwise they're loaded on startup. You're suggesting that if we fail to load the settings due to a memory error, we should just leave the data in place and load it on the next startup?

    If there is indeed a difference in behaviour when pushing settings when the app is running versus not running, then I feel this is a little user-unfriendly.

    The difference in behavior occurs because when the app is running you hold all of the available memory, and at startup you haven't had a chance to horde it all.

    Is it just the case where I need to tell users to exit the app before changing settings?

    This would reduce the memory load at the time the settings are loaded.

    Some of the same data fields consistently crash in the sim though (also 935) when settings are changed (without killing the app first).

    I have mentioned how helpful it is to have test cases before, right? :-)
  • That's why I suggested once that it would be nice if an app could somehow opt out of run-time settings changes

    I concur and i think i also suggested this in the past.

    If the app isn't going to do anything with the new settings it makes no sense trying to have them loaded.

    the preferably way would be that the connect iq framework can detect that reloading settings isn't necessary, but in case this isn't possible i wouldn't mind flipping a switch in the manifest or jungle file to specify that I don't support setting changes in this app.