App crash after settings changed

I just updated my app to the store and found out the app crashes if I touch the new app settings. Any input on how to debug this? On sim everything is fine and everything even works on the device (Epix) as long as I don't edit the settings in Garmin Connect.

Also, an option to quickly revert the app to an earlier version in the store would be great...

If it helps, these are the last lines from device's CIQ_LOG (the crash occurs when trying to read a value from the settings with: Application.getApp().getProperty("UseAtmCorr")):

ERROR: Unhandled Exception
DETAILS: Failed invoking <symbol>
STORE_ID: c9012c4e998c4a0ea567b1e1c6078401
WARNING: Unable to close bike power sensor
STORE_ID: c9012c4e998c4a0ea567b1e1c6078401


I've tried adding onSettingsChanged in the application class, but it's basically an empty method (with only a call to superclass onSettingsChanged) since I could not figure what to put there.
  • Hi,

    it's not as easy as it seems to be, at the moment.

    You should handle a few special cases:

    1) Check returned properties for NULL and empty string. If your PROP is returned as NULL then you can't execute expressions like "if (PROP > 0)...".

    2) Check data type of the returned property (you can use instanceof operator). You can have a list of items with numeric values, but there was (is?) a small bug in Android Garmin Connect Mobile which was returning the value as string.

    3) There is also a bug in Garmin Express for Windows v 4.1.10.0 which is returning an index of the list-entry instead of its value.


    There is also s small snippet how to make your applications responsive in second for changed properties.

    // Implement your App class like this (just example)
    class MyOwnApp extends App.AppBase {
    var view = null;
    function onStart() {
    }
    function onStop() {
    }
    function getInitialView() {
    view = new MyOwnView(); // save instance of the View
    return [view];
    }
    function onSettingsChanged()
    {
    if (view != null) {
    view.onSettingsChanged(); // pass the call of onSettingsChanged directly to the View
    }
    }
    }
    ---------------

    class MyOwnView extends Ui.View {
    // add onSettingsChanged() method also to your View
    function onSettingsChanged() {
    reloadResources(); // here you can load new properties.. you should call it also from onLayout() to load properties for the first time
    Ui.requestUpdate(); // refresh immediatelly
    }
    ...
  • What exactly happens when the settings change? Is there anything I should do in the app's onSettingsChanged -method like refresh the property storage manually? If I've understood correctly, the setting's properties should always be present as they are defined in the resource file and therefore a value should always exist (unless the user has explicitly emptied it).

    Basically I am just reading the setting using the getProperty(propertyName) and this AFAIK should pull the data from some magical storage which should always contain the up-to-date setting data (updated by the mobile app). The setting in question is of type boolean, so under what conditions it can ever return anything other than true/false?

    The row I suspect that is causing the crash is below. To me it seems that getProperty might be returning a null value (as the code should be able to evaluate any other type of value) and cause the app to crash. I just have no idea why it is doing that.

    addRow("Atm correction", Application.getApp().getProperty("UseAtmCorr") ? "on" : "off");
  • When a user changes settings, it is stored into .SET file in /GARMIN/APPS/SETTINGS and CIQ virtual machine is informed that settings has changed. Only way how the virtual machine can give you that info is call of onSettingsChanged() method. And it's up to you to implement it and handle/reload your settings. If you reload your settings in onSettingsChanged(), you can be sure that it retrieve actual values.

    And to your code.. yes.. it will crash if your property has returned NULL or data type other than boolean. You should check it and set some default value in that case.
  • ok. I need to check the that the returned value truly is a boolean, thanks :)

    Just to be clear: since my code is using the app's getProperty method instead of some cached value AND the getProperty should always return the current value of the queried property regardless if the settings have changed or not, I do not need to do anything in the onSettingsChanged and I can choose not to implement it at all, right?
  • You don't need to implement onSettingsChanged() if you call app.getProperty() each time you use it.

    Typical use case for onSettingsChanged() is for watchface, where you load properties just once in onLayout (to minimize battery consumption and better performance). But a user wants to see his property changes to be effective immediatelly. That's the case you should implement onSettingsChanged() and refresh the look instantly.
  • Petr,

    thanks for helping me to resolve this. In the end the problem was the android bug that causes the getProperty to return the value as strings. A nice typecheck and toFloat solved it. Luckily the values are always accessed through a wrapper, so I had to change the code in just one place :)
    function getSightHeight() {
    var val = Application.getApp().getProperty("SightHeight");
    if(val instanceof Toybox.Lang.String) {
    val = val.toFloat();
    }
    return (val <= 0) ? 1 : val;
    }
  • Thanks.

    Your message help me to correct my issue.

    the android bug that causes the getProperty to return the value as strings
  • The problem still exists on Android. Thanks for your solution I did not understand my error