ERA reports some cases of unhandled exception from Application.Properties.getValue() in onLayout()

I'm getting some ERA reports of an unhandled exception when calling Application.Properties.getValue() from onLayout() - but I've no idea why it could be happening ...

It is happening in both an app and a watchface - and it's always on the very first call to access the properties after starting up.

The property is defined in the properties.xml just like normal:

    <property id="pg" type="boolean">false</property>  <!-- position got -->

And is accessed just with a normal call:

    var v = Application.Properties.getValue("pg");

It clearly works for most people using the app, but why are there some instances of exceptions being created?

The documentation says these are the possible exceptions:

  • (Toybox::Lang::UnexpectedTypeException)

    Thrown if key is of type null, Array, or Dictionary

    (Toybox::Application::Properties::InvalidKeyException)

    Thrown if key does not exist in Application Settings

Is there some other exception possible here?

Any suggestions for how I could debug this?

  • Check the FW versions for the devices in the ERA reports, as there is an issue where apps can be installed on devices without the proper firmware.

    For row devices, you can see what the latest FW is by looking in the forum for that specific device, and there's usually a sticky at the top where you can see the latest production FW version.

  • Ahh, after checking the versions for each device like you suggest, it looks like they are all on the latest firmware. These are the ones Era reports so far:

    fēnix® 6 Pro / 6 Sapphire: 5.00
    fēnix® 5 Plus: 10.00
    fēnix® 6X Pro / 6X Sapphire / 6X Pro Solar: 5.00
    Forerunner® 245 Music: 4.00

  • For Properties, the key must exist or you'll get an exception.  Could be something odd happened to the .set file (maybe an error when saving changes?)

    What you can do is put the call in a try/catch, and in the catch block, supply a default.

  • Strangely it seems to be my most occurring bug - 43 times overnight, and just got a new one for:

     fēnix® 5 / quatix® 5: 15.10

    Using a try/catch is a good idea - for that property replacing it with a default should work (since it is just helping to remember your last known gps position), even if it means adding more logic to the code. Then I guess I also need to check every single value read from Properties.

    But if it will happen for other properties too, that could be problematic as I use some of them to remember some user data … it may be better to crash rather than overwrite user data with some default value which then gets saved back to the properties. It depends whether it's just a temporary crash and the next time the app starts up the data will be read successfully, or if it is a permanent failure to the properties file. So it would be good to find out what it is ...

  • Could it just be a problem trying to access properties in onLayout? I.e. too early in the startup. Or should you be able to access properties at any time?

  • Maybe just use a try/catch for every property read and if any read fails then stop doing anything normal in the app and display an error message to the user asking them to contact me. At least that is nicer than a crash.

  • for that property replacing it with a default should work (since it is just helping to remember your last known gps position),

    I wouldn't use a Property for that.  I'd put it in Storage (well, in fact I do).  When you have things as Properties it increases the size of the .set, and the things that need to be sent back and forth when doing settings, and also the memory used when setting change.

    Unless there's a setting for something, I put it in Storage.

  • It should work with a Property though? (In theory Slight smile!)

    As I understood it, it's just a tradeoff between using storage and properties:

    Storage = slower but less memory usage

    Properties = faster but more memory usage (because of the settings memory copy that you mention)

    In my tests this actually made a significant difference to the startup speed of the watchface version of my app by not loading anything from storage, so I moved everything out of storage and into the properties as the memory usage is not a problem for this version.

    If you think the properties are not reliable, then I will switch back to using storage again! But I assume that both storage and properties should be reliable storage for data.

  • Not really, as Proprieties consume more resources.  You can easy see this when you change settings while an app is running in the sim and there's the memory spike.  Storage only loads one key at a time, and for something like what you're doing, that only happens one in an app lifecycle and is only loaded once and then is gone.

    Also with Properties, when a user changes a setting, data gets sent back and forth to the phone.

    You can use the ObectStore (the old storage) which is more efficent, but will takke a bit more runtime memory.

    And as you see in this case, Properties can cause issues if something is odd with the .set.

    for a bunch of reasons, I'd never use Properties instead of local storage for things that are only local.

  • In my tests it was about 150ms for each read from storage (whatever the size), whereas accessing properties was approximately 5ms - so that speed difference is a lot.

    And yep it only happens when starting or closing the watchface - but that's also the time when it is most noticeable Slight smile It's definitely faster now using properties than it was using storage.

    I'd assume if the properties file can get corrupted then the storage file can also get corrupted just as easily? Or do you think that the storage file is more likely to be stable?

    When you mention the ObjectStore, is that via Application.AppBase.setProperty() & getProperty()? Is it better (& different?) to use that instead of Application.Properties? If you think I should be using that instead I'll check it out.