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

  • for readability, you probably want to use the tags vs hard coded values,

    so instead of

    dc.drawText(tx.ty,stateLabel,font,5);

    use

    dc.drawText(tx.ty,stateLabel,font,Graphic.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);

  • I guess I need to read up on enum! ;)

    Thanks,

  • Going a bit deeper into that, though;

    The enum and array fix my lookup of colours to be more efficient, but still readable.

    However, I'm still left with the string lookup where I had Rez.Strings[currentState];

    I can, of course, do the same thing here;

    var strings = [:Stopped,:Paused,:Running]

    and then

    currentState = RUNNING;

    var stateLabel = WatchUi.loadResource(Rez.Strings[strings[currentState]]);

    Which (as I use a loadStr() method to cut out the gobbledegook) sort of works, but is there a better way to map the string symbols?

  • Rewritten as your version:

    //////////////
    // In initialize
    enum { STOPPED, PAUSED, RUNNING }
    fgColours = [Graphics.COLOR_RED,Graphics.COLOR_ORANGE,Graphics.COLOR_GREEN];
    bgColours = [Graphics.COLOR_BLACK,Graphics.COLOR_GREY,Graphics.COLOR_WHITE];
    strings = [:Stopped,:Paused,:Running];
    ///////////////////
    // 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[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
    }

  • You also may want to consider caching what you get from Rez and not doing the loadResource every second in onUpdate.

    That cache could again be a simple array.

  • Hmm...

    I guess I'm hitting pain points in a different way to you!

    I know you are right on a purely "what is a sensible and good idea" level, but every additional property defined on a class adds to the memory load. And while, yes I know, loadResource will consume memory whilst running... I have also found that there are occasions where the cost of doubling up the memory (one to hold the string to choose, the other the chosen string during onUpdate) can be prohibitive as although the processor is doing less work, I quite literally do not have the memory for the extra var definition and stored values.

      

  • loadResource takes more time. No sense doing things repeatedly that only need to be done once. ("has" is an example I used a bit back)  Not sure why you're talking about an additional property.

  • Not sure why you're talking about an additional property

    A trivial example of the kind of problem and the kind of refactoring I have encountered:

    During onLayout, I calculated layout positions and strings for text. In order for these to be used in onUpdate, I needed to store them. Something like this:

    // In class definition
    var tx; // Text x
    var ty; // Text y
    var tStr; // Text string to display
    var tFont; // A font that fits layout
    var tAlign; // The text alignment in use for layout
    
    // During onLayout
    tx = calculatedValue...;
    ty = calculatedValue...;
    tStr = calculatedValue...;
    tFont = calculatedValue...;
    tAlign = calculatedValue...;
    
    // During onUpdate
    dc.drawText(tx,ty,tStr,tFont,tAlign);

    Which is... to my mind... the proper way to do it.

    But... when running so painfully close on memory limits due to other things that are going on, I found doing this could save me a ridiculous amount of actual runtime memory.

    // In class definition
    
    // During onLayout
    
    
    // During onUpdate
    var tx = calculatedValue...;
    var ty = calculatedValue...;
    var tStr = calculatedValue...;
    var tFont = calculatedValue...;
    var tAlign = calculatedValue...;
    dc.drawText(tx,ty,tStr,tFont,tAlign);

    Maverick? Yes.

    Totally counter-intuitive? Yes.

    Did I feel kinda dirty and unclean afterwards? Yes.

    But...

    After a series of refactorings of this nature, I had saved about 2KB in runtime memory which was enough to make something run where previously it had not.

    so instead of

    dc.drawText(tx.ty,stateLabel,font,5);

    use

    dc.drawText(tx.ty,stateLabel,font,Graphic.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);

    Which is also why I wrote the 5 there!

    Writing "Graphics.TEXT_JUSTIFY_CENTER|Graphic.TEXT_JUSTIFY_VCENTER" is indeed a lot more readable, but it also uses more memory!

    var t = 5;

    is 20 bytes more efficient than

    var t = Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER;

    Doesn't sound a lot, but if you have several different display paths defined in code, those small numbers can add up and as creating a method call to simplify things can often cost more than simply repeating the line of code...

    Not everything I do in Garmin code is stuff I would want to show to a teacher!

  • So you meant variables and not properties.  OK..

    When you look at memory, you'll see pretty much the same if you set the vars in initialize or in onUpdate.  The difference being when that memory is allocated.  In initialize, it's always used.  In onUpdate, when the function runs, so things like idle memory will be lower (that's what you see on the bottom line of the sim).

    I use "efficient" in a different way in that I consider how fast things run, as that impacts battery, etc, but maybe not as obvious.  But you can use Sys.getTimer() to tune your code. 

    I'll sacrifice a few bytes if it executes faster. (like not calling "has" all the time or loading resources repeatedly).  If you've not done anything with onPartialUpdate, that's a case where speed is #1, as you are limited to an avg of 30ms each time it's called.

    As far as memory, you want to a bit back from the edge, as something in the environment could change where there's a a bit more memory needed, or a bug comes up that takes a bit to fix..

  • you'll see pretty much the same if you set the vars in initialize or in onUpdate

    Sorry, my pseudo-code was clearly unclear!

    What I am discussing is the difference between this:

    class SomeClass {

    hidden var someVar; // Var is a property of the class, defined as part of the class definition

    function myMethod() {

    someVar = "bob";

    }

    }

    And this:

    class SomeClass {

    function myMethod() {

    var someVar = "bob"; // Var is locally scoped, used in memory during the method call, then cleaned up as method completes

    }

    }

    And, believe me, the difference between having stuff as part of a class definition rather than as a throwaway is significant.

    As far as memory, you want to a bit back from the edge

    Want to, yes.

    I also want quite a number of things to change in the political, environmental and sociological realms... Sometimes you gotta go with what you've got. 

    And to put this into perspective, before I started, even without .FIT fields on this specific project, it wouldn't run on my 735xt. Now it runs with .FIT fields and a margin of error. Taken, en masse, I've refactored away more than 4KB in runtime memory without loss of functionality. .FIT fields chew through memory so I still have different numbers of fields on different devices but I can run safely with .FIT fields on all the devices I support.