Help with readKeyInt

I am working with "readKeyInt" to draw several bitmaps when the user uses the settings function.

The sim loads well with all the functions (time, background, etc). However, when I select the theme, the bitmap does not load upon command. Now, if I select a new theme on the simulator and then re-run the app, it loads the new image. The sim does not allow me to change the theme similar to how the background color is changed.

Has anyone experienced this challenge? Can someone point me in the right direction to enable the themes upon command?

  • readKeyInt is used to read a Number (integer) from properties, and insure it's a Number, and return a default if the key isn't valid. How are you trying to use it?  It's just a wrapper function to do a couple simple things when reading settings.  It was written long before Application.Properties so it only uses the old call of Application.Properties.getValue()

  • this is what i have:

          set_theme = readKeyInt(Application.getApp(),"theme",99);

          switch (set_theme) {

            case 0:

            b_pic = WatchUi.loadResource(Rez.Drawables.pic1);

            break;

            case 1:

            b_pic = WatchUi.loadResource(Rez.Drawables.pic2);

            break;

    then i have the function readKeyInt(myApplication,key,thisDefault) 

  • What makes you think the problem is with readKeyInt()? Why is your default value 99?

    Have you tried adding a System.println() debug call after the readKeyIntCall() to see when it's being called and what the value of set_theme is?

    For that matter, when *is* readKeyInt() being called? The code snippet doesn't have enough context.

    I assume you want that code run at startup and when app settings are changed. (I assume that when you say "I select a new theme on the simulator", you mean that you use app settings that you have defined to change the value of the property "theme".) Based on what you said, it sounds like the code already runs at startup.

    Are you calling this snippet of code in onSettingsChanged()? After you load the resource, do you call WatchUi.requestUpdate()? How do you use b_pic?

  • Not sure where the problem is but I went to readKeyInt since I have tried multiple codes and this one appears to do some of the job. I am close enough that I feel it may be it... or I may be completely off. I am open to suggestions for sure.

    I have used a regular dc.drawBitmap and it worked well with only 1 image. I have tried other methods but the bitmaps do not load well due to memory. When I used readKeyInt, the sim works with one image only. If I use the app settings editor I see the settings function for the rest of the images, but it does not push each image to the sim. I literally have to reload in eclipse and then I see the new image. 

    I have not tried the system.printIn().

    It is being called onUpdate with dc.drawBitmap(width/7,height/9, b_pic);     Maybe the issue is here??

    re: your 4th paragraph: Yes, the vision is the code to run at startup and when app settings are changed. The code is in the function onLayout(dc). Is this not the location it should be?

    The snippet code is used as you mentioned. Do I need to add anything else?

    function onSettingsChanged() {

            WatchUi.requestUpdate();

        }

  • Thanks for the context!

    The problem is that your code for loading the resource is in onLayout(), which is only going to be called once (and not when settings change). From the docs:

    developer.garmin.com/.../View.html

    onLayout() is called before the View is shown to load resources and set up the layout of the View.

    To fix this, I think you can put that snippet (for loading the resource) in a function, and call it in two places:

    - onSettingsChanged()

    - onLayout()

    If you're testing things in the sim, I highly suggest using System.println() so you can validate that your code is actually running when you think it's running. Every dev has been in a situation where we assume something works one way, but in fact it works differently, and "println/console.log" debugging is one of the easiest ways to test these assumptions.

    As far as readKeyInt() goes, I think it's understood that this is just a function for reading a value from app properties. It doesn't load anything or cause anything to be drawn on its own.

    The real issue has to be with when that value is read, and what is done with the value. But again, if you really wanted to know if readkeyint is the problem, the easiest way to find out would be to use System.println(). (The 2nd-easiest way would be to use the debugger.)

  • I think I am close.

    Snippet. What do you mean? Which part?

    I assume is the following and I went ahead and wrote what I display below. When I run the sim I see the initial image but then an error comes back when I select a new theme. It tells me “out of memory error” and failed invoking symbol line 34 which is the  b_pic = WatchUi.loadResource(Rez.Drawables.pic2);

    Modified code in View.mc:

    function onLayout(dc) {

    View.onLayout(dc); 

    set_theme = readKeyInt(Application.getApp(),"theme",0);

          switch (set_theme) {

            case 0:

            b_pic = WatchUi.loadResource(Rez.Drawables.pic1);

            break;

            case 1:

            b_pic = WatchUi.loadResource(Rez.Drawables.pic2);

            break;

    Code written in App.mc

    extends Application.AppBase {

    var set_theme = 0

    function onSettings Changed() {
    WatchUi.requestUpdate();

    var b_pic;


    set_theme = readKeyInt(Application.getApp(),"theme",0);

          switch (set_theme) {

            case 0:

            b_pic = WatchUi.loadResource(Rez.Drawables.pic1);

            break;

            case 1:

            b_pic = WatchUi.loadResource(Rez.Drawables.pic2);

            break;



  • Yes, that's the code I meant.

    Note that I didn't suggest copying and pasting code like you did, but making it a separate function. Copying and pasting large blocks of code like that wastes memory.

    Anyway, since you're running out of memory when loading the resource, it's probably because memory spikes around the time that onSettingsChanged() is called, and because loading resources takes a lot of memory. You will probably have to split the read of the app property and the loading of the resource into two pieces. I can't guarantee that this will work, but you can give it a try. If it still doesn't work, you'll have to play around with your app to save memory, or give up the idea of changing the theme dynamically.

    /* In App.mc */
    
    var theme = 0;
    
    function getTheme() {
        return theme;
    }
    
    function readSettings() {
        theme = readKeyInt(Application.getApp(), "theme", 0);
    }
    
    function onSettingsChanged() {
        readSettings();
        WatchUi.requestUpdate();
    }
    
    function onStart() {
        readSettings();
    
        // ...
    }
    
    /* In View.mc */
    
    var currentTheme;
    
    function initialize() {
        currentTheme = Application.getApp().getTheme();
    }
    
    function applyTheme() {
        switch (currentTheme) {
            case 0:
                b_pic = WatchUi.loadResource(Rez.Drawables.pic1);
                break;
    
            case 1:
                b_pic = WatchUi.loadResource(Rez.Drawables.pic2);
                break;
        }
    
    }
    
    function onLayout() {
        applyTheme();
    }
    
    function onUpdate() {
        // Add this code before everything else:
        //
        // check if theme has changed
        var newTheme = Application.getApp().getTheme();
        if (currentTheme != newTheme) {
            currentTheme = newTheme;
            applyTheme();
        }
    
        // ...
    }

    You could also try setting b_pic to null before loading the new resource, although I don't think it should make a difference. e.g.

    function applyTheme() {
        b_pic = null;
        switch (currentTheme) {
            case 0:
                b_pic = WatchUi.loadResource(Rez.Drawables.pic1);
                break;
    
            case 1:
                b_pic = WatchUi.loadResource(Rez.Drawables.pic2);
                break;
        }
    
    }
    

  • Brilliant. It worked. Thank you!

    I just have to figure how to use the system.printIn() as you suggested. Do I need to remove it before sending the file to Garmin or is it okay to leave it...?

  • No worries. You should remove it because it wastes memory in two ways:

    1) The code itself makes your program slightly bigger

    2) (more importantly) when System.println actually runs, there's a memory spike which can crash your program

    If your code is working, you don't need System.println(), but let's say you wanted to see when your call to readKeyInt() was being run, and what the return code was. You could've added a System.println() call like this:

    set_theme = readKeyInt(Application.getApp(),"theme",0);
    System.println("readKeyInt(..., 'theme') = " + set_theme);

  • Curious...do you know how to loop the images?