How to define own map keys like :bluetooth, :wifi

Currently I define map keys like following:

static const KEY_X = "x";

But I saw that something like following is possible as well:

var isWifiConnected = connectionInfo[:wifi].state == System.CONNECTION_STATE_CONNECTED;

Is it possible to define such variables like the ":wifi" myself aswell?

Top Replies

All Replies

  • Yes. 

    Read up on Symbol developer.garmin.com/.../Symbol.html

    They are great, also very lightweight. 

  • Thanks. So sadly I can use them only rarely because most keys I use are also used for persistance already. But at least some keys can be optimised

  • Accessing by symbol may not be as efficient as using an index, and memory wise, would be a simple object, like a Number.

    In the line of code you posted, that would also crash on a device without wifi, as :wifi doesn't exist on those.

  • Documentation says, that if the device does not support e.g. wifi, connectionInfo[:wifi] will return null. Yes, my example would crash but what you see sounds like following would crash also:

    var connectionInfo = settings.connectionInfo;
    var supportsBluetooth = connectionInfo[:bluetooth] != null;
    var supportsWifi = connectionInfo[:wifi] != null;
    var supportsLTE = connectionInfo[:lte] != null;
    
    var stateBluetoothIsConnected = supportsBluetooth && connectionInfo[:bluetooth].state == System.CONNECTION_STATE_CONNECTED;
    var stateNetworkIsConnected = (supportsWifi && connectionInfo[:wifi].state == System.CONNECTION_STATE_CONNECTED) ||
    							(supportsLTE && connectionInfo[:lte].state == System.CONNECTION_STATE_CONNECTED);

    It works in the emulator although the fenix 6x does not support LTE...

  • Thanks. So sadly I can use them only rarely because most keys I use are also used for persistance already. But at least some keys can be optimised

    Well...

    I asked a question here that I think is relevant to read through: https://forums.garmin.com/developer/connect-iq/f/q-a/218088/is-there-a-better-way-to-select-resources

    The outcome was a way better understanding by me of how symbols work and a revolutionary understanding of how to get memory down AND improve the readability of my code.

    For example:

    If, in Strings, I define a string for state label (Rez.Strings.Stopped,Rez.Strings.Paused,Rez.Strings.Running) and those have settings that go with them, I can do something like this:

    //////////////
    // In initialize
    fgColours = {};
    fgColours[:Stopped] = Graphics.COLOR_RED;
    fgColours[:Paused] = Graphics.COLOR_ORANGE;
    fgColours[:Running] = Graphics.COLOR_GREEN;
    
    bgColours = {};
    bgColours[:Stopped] = Graphics.COLOR_BLACK;
    bgColours[:Paused] = Graphics.COLOR_GREY;
    bgColours[:Running] = Graphics.COLOR_WHITE;
    
    ///////////////////
    // In compute...
    if(aTestYouWrote) { currentState = :Running; }
    else if(someOtherTestYouWrote) { currentState = :Paused;    }
    else {  currentState = :Stopped; }
    
    // In onUpdate, use state to set foreground, background and label
    var stateLabel = WatchUI.loadResource(Rez.Strings[currentState]);
    dc.setColor(fgColours[currentState],bgColours[currentState]);
    dc.clear();
    dc.drawText(tx.ty,stateLabel,font,5);
    // Additional display code to customise for each state... 
    if(currentState == :Running) {
        // Running display
        
    } else if(currentState == :Paused) {
        // Paused display
    } else {
        // Stopped display
    }

    Now, obviously, that's pseudo code and there are ways to make it more efficient / smaller / better, but the concept is that a readable Symbol used in code means I can load exactly what I want with minimal code and it is easy to both read and to manage linked strings, JSON resources, image resources etc.

  • For built-in objects, I think you're meant to use "has" to check that it allows that property before checking it is null.

    On devices that don't allow it, even reading the property can cause a crash.

  • One thing to note about "has" (since we're talking about symbols), is that I advice using it sparingly, as it's not a simple operation.  IT's got to look around for the symbol.

    Do it once when an app starts and set a boolean, as it won't be changing at runtime and no need to use it on every call to onUpdate() for example.

  • var supportsLTE = connectionInfo[:lte] != null;

    This would be false on a f6x

    and there is a much simpler way to set stateNetworkIsConnected 

    var sSettings=Sys.getDeviceSettings();

    hasConnectionAvail=(sSettings has :connectionAvailable); //this only needs to be done when the app starts

    var stateNetworkIsConnected==(hasConnectionAvail) ? sSettings.connectionAvailable : sSettings.phoneConnected;

    This works on any device to see if the device is connected to something

  • for 

    bgColours = {};
    bgColours[:Stopped] = Graphics.COLOR_BLACK;
    bgColours[:Paused] = Graphics.COLOR_GREY;
    bgColours[:Running] = Graphics.COLOR_WHITE;

    you can replace that with 1 line:

    bgColours={:Stopped=>Graphics.COLOR_BLACK,:Paused=>Graphics.COLOR_GRAY,:Running=>Graphic.COLOR_WHITE};

    or to be more efficient,

    enum {

      STOPPED,PAUSED,RUNNING

    }

    and then 

    bgColours=[Graphics.COLOR_BLACK,Graphics.COLOR_GRAY,Graphic.COLOR_WHITE];

    and to reference something,

    bgColours[RUNNING]

    for example  A simple array of numbers vs a dictionary.

  • thanks for all the tipps, I'll use them to optimise my watchfaces memory usage