The properties won't change after the saving action if the memory usage is near the limit

Hi,

I was developing a new watchface.

When I run it on venu2 simulator, all works fine. But if I start it on a fr245 sim, the properties won't be saved.

It is my first time to witness such a weird phenomenon.

You can see the demo here https://youtu.be/_9wMeTRnUHs

Did you encounter the similar issue.

Here is my code snippet, the code works when the memory has a lot available

function initialize() {
hourMinFont = Ui.loadResource(Rez.Fonts.HourMinFont);
secTempFont = Ui.loadResource(Rez.Fonts.SecTempFont);
smallCharFont = Ui.loadResource(Rez.Fonts.SmallChars);
iconsFont = Ui.loadResource(Rez.Fonts.IconsFont);
themePallete = WatchUi.loadResource(Rez.JsonData.theme_pallete);

isSquareDevice = layout[21] == 1;
arcLineBackgroundColor = layout[17] == 0? Graphics.COLOR_DK_GRAY:Graphics.COLOR_WHITE;

dateUtils = new LunarDateUtils();

var location = Activity.getActivityInfo().currentLocation;
if (location) {
// Sys.println("the location is not empty");
location = location.toDegrees(); // Array of Doubles.
gLocationLat = location[0].toFloat();
gLocationLon = location[1].toFloat();
Storage.setValue("_gLocationLat", gLocationLat);
Storage.setValue("_gLocationLon", gLocationLon);
}
if(testMode){
Storage.setValue("_gLocationLat", 30.52);
Storage.setValue("_gLocationLon", 114.31);
}
onSettingsChanged();
// Sys.println("show second?:" + alwaysShowSeconds);
do1hz = (Ui.WatchFace has :onPartialUpdate );
canDo1hz=do1hz;

WatchFace.initialize();
initTrial();
}

function checkTheme() {
Sys.println("Checking themes......................");
var theme_code = Application.getApp().getProperty("theme_code");
//这段代码是为了兼容老的配置数据
if(theme_code < 30){
theme_code = ("3"+theme_code).toNumber();
Application.getApp().setProperty("theme_code",theme_code);
}
var last_theme_code = Application.getApp().getProperty("last_theme_code");
if (last_theme_code == -1 || last_theme_code != theme_code) {
Sys.println("A theme change detected......................");
var theme = themePallete[""+theme_code];
backgroundColor = theme[0];
hourColor = theme[0];
Sys.println("hourColor changed in the check theme:"+hourColor);
if(App.getApp().getProperty("WeatherIconColorFollowTheme")){
weatherIconColor = theme[0];
App.getApp().setProperty("WeatherIconColor", theme[1]);
// Sys.println("weatherIconColor"+weatherIconColor);
}
App.getApp().setProperty("hourColor", theme[1]);//颜色的后面一个就是颜色对应的代码编号

bottomMeterAccentColor = theme[0];
App.getApp().setProperty("bottomMeterAccentColor", theme[1]);

topMeterAccentColor = theme[0];
App.getApp().setProperty("topMeterAccentColor", theme[1]);
Application.getApp().setProperty("last_theme_code",theme_code);
}
}

function onSettingsChanged() as Void {
Sys.println("View settings is been updating");
alwaysShowSeconds = App.getApp().getProperty("AlwaysShowSeconds");
showColon = App.getApp().getProperty("ShowColon");
disableSecondDisplay = App.getApp().getProperty("DisableSecondDisplay");

drawShadow = App.getApp().getProperty("DrawShadow");

showAmPmSymbol = App.getApp().getProperty("showAmPmSymbol");

hourColor = getColor(App.getApp().getProperty("hourColor"), Gfx.COLOR_WHITE);
Sys.println("hourColor changed in view settings changed:"+hourColor);


minColor = getColor(App.getApp().getProperty("minuteColor"), Gfx.COLOR_WHITE);

secondColor = getColor(App.getApp().getProperty("secondColor"), Gfx.COLOR_WHITE);


ampmColorProperty = App.getApp().getProperty("ampmColor");
ampmColor = getColor(ampmColorProperty,Gfx.COLOR_WHITE);

useColorfulBatteryIcon = App.getApp().getProperty("useColorfulBatteryIcon");

showBottomDataAreaData = App.getApp().getProperty("ShowBottomDataAreaData");
showTopDataAreaData = App.getApp().getProperty("ShowTopDataAreaData");
topDataAreaDataType = App.getApp().getProperty("TopDataAreaDataType");
bottomDataAreaDataType = App.getApp().getProperty("BottomDataAreaDataType");


grid1DataType = App.getApp().getProperty("Grid1DataType");
grid2DataType = App.getApp().getProperty("Grid2DataType");
grid3DataType = App.getApp().getProperty("Grid3DataType");

grid4DataType = App.getApp().getProperty("Grid4DataType");
grid5DataType = App.getApp().getProperty("Grid5DataType");
grid6DataType = App.getApp().getProperty("Grid6DataType");

grid1DataColor = getColor(App.getApp().getProperty("Grid1DataColor"),Graphics.COLOR_WHITE);
grid2DataColor = getColor(App.getApp().getProperty("Grid2DataColor"),Graphics.COLOR_WHITE);
grid3DataColor = getColor(App.getApp().getProperty("Grid3DataColor"),Graphics.COLOR_WHITE);

grid4DataColor = getColor(App.getApp().getProperty("Grid4DataColor"),Graphics.COLOR_WHITE);
grid5DataColor = getColor(App.getApp().getProperty("Grid5DataColor"),Graphics.COLOR_WHITE);
grid6DataColor = getColor(App.getApp().getProperty("Grid6DataColor"),Graphics.COLOR_WHITE);

topMeterDataType = App.getApp().getProperty("TopMeterDataType");
bottomMeterDataType = App.getApp().getProperty("BottomMeterDataType");

//顶部进度条的色彩
topMeterAccentColor = getColor(App.getApp().getProperty("topMeterAccentColor"),Graphics.COLOR_WHITE);

//底部进度条的色彩
bottomMeterAccentColor = getColor(App.getApp().getProperty("bottomMeterAccentColor"),Graphics.COLOR_WHITE);

lunarDateFormat = App.getApp().getProperty("lunarDateFormat");

solarDateFormat = App.getApp().getProperty("solarDateFormat");


superBatterySaverMode = App.getApp().getProperty("superBatterySaverMode");
disableWeather = App.getApp().getProperty("DisableWeather");
noWeatherEmojiType = App.getApp().getProperty("NoWeatherEmojiType");

topHugeAreaDataType = App.getApp().getProperty("topHugeAreaDataType");
bottomHugeAreaDataType = App.getApp().getProperty("bottomHugeAreaDataType");

weatherIconColor = getColor(App.getApp().getProperty("WeatherIconColor"),Graphics.COLOR_WHITE);

isAPACDevice = Application.getApp().getProperty("IsAPACDevice");
if(!isAPACDevice){
gWeatherProvider = 0;
}


checkTheme();

}
  • Yes, you want to use getValue/setValue instead of getProperty/setProperty if the device supports those calls, which can be determined with "has"

  • can you elaborate on that? Why do I really NEED to use has? I do something else instead that saves some code:

    (:no_api2, :memory16K, :inline)
    function setConfig(key as PropertyKeyType, val as PropertyValueType) as Void {
      MyApp.setProperty(key, val);
    }
    (:api2, :memory32K, :inline)
    function setConfig(key as PropertyKeyType, val as PropertyValueType) as Void {
      Properties.setValue(key, val);
    }

    and in monkey.jungle I have:

    base.excludeAnnotations = base;no_api1_3;no_api2;memory16K;black_and_white
    epix.excludeAnnotations = base;api1_3;api2;memory32K

    I don't know of any other CIQ device that can have CIQ that is not at least 1.3. But that might be a mistake of mine in the way I interpret to not too clear data I found here: https://developer.garmin.com/connect-iq/compatible-devices/ and that was the reason I opened this feature-request to improve the documentation: https://forums.garmin.com/developer/connect-iq/i/bug-reports/improve-documentation-add-api-levels-and-system-levels-to-device-reference
  • You don't need to use has, but you can simplify your code and jungles if you do

  • well that depends how you look at it :) My solution might be not straightforward and a bit more complex, but it decreases code size, uses less battery, runs faster...

    The only question that I'm not yet 100% sure of is whether I am right in how I interpret the devices table's API level column. Hmmm, actually I had a look at it now, and now it's clear that it's not correct. I mean for the Fenix 6 API: 3.3.0 is listed which is the maximum api level. If someone did't upgrade to 21.00 or higher then they still are on 3.2.x. So my jungle file might need some adjustment (to set the excludeAnnotations for some other devices that have a MINIMUM api that is less than 1.3). But that's what this feature request is about: https://forums.garmin.com/developer/connect-iq/i/bug-reports/improve-documentation-add-api-levels-and-system-levels-to-device-reference

  • wow, You are really an expert in using annotation.

    base.excludeAnnotations = base;no_api1_3;no_api2;memory16K;black_and_white

  • thanks Slight smile
    20 years ago in my 1st job after the uni I wrote some games on SonyEricsson phones. This was still before the downloadable apps time so these games were in the ROM. And they also had much less RAM than the CIQ apps have even on epix 1 :) So I like to tweak things and even if it's not necessary for the app, if I can find a way to make the code a few bytes less it's a fun game for me. And I did manage to decrease the code size on the old watches so much that I could even "backport" some features because I had some spared bytes...

  • I have similar annotations for some of my apps, but tbh it's a nightmare to maintain. Every time you add a new annotation in a given "dimension" (like screen type or API), you have to go and modify all existing usages in monkey.jungle. At least the build will fail if you forget to do it (as you'll have multiple definitions of certain symbols).

    e.g.

    base.excludeAnnotations = $(round_240_screen_excludes);$(fr935_font_excludes);ciq1;ciq1_notf3;ciq1_f3

    fr935_font_excludes = approachs60_font;fr735xt_font;vahr_font;fenix5s_font;va3_font;default_font

    round_240_screen_excludes =
      va4s_screen;round_390x390;round_280x280;rectangle_220x240;
      round_260x260;round_218x218;semiround;rectangle;tall;
      va3_screen;noncircular;round_f3

    inb4 "that's terrible code" (I know it is lol.)

    if I can find a way to make the code a few bytes less it's a fun game for me

    I spent a lot of time doing this as well, but tbh it's the least fun part of monkey c development for me. It was satisfying at first to find various tricks for saving memory but at some point it becomes a mechanical grind.

  • Haha, I am using another approach to manage the difference points like screen shapes, screen materials across models. 

    vivolife.sourcePath = $(vivolife.sourcePath);source-round-240x240;source-owm
    vivoactive4.sourcePath = $(vivoactive4.sourcePath);source-round-260x260;source-gw
    vivoactive4s.sourcePath = $(vivoactive4s.sourcePath);source-round-218x218;source-gw

    fenix7s.sourcePath = $(fenix7s.sourcePath);source-round-240x240;source-gw
    I think I need annotations to manage more small functionalities difference like ciq version and api difference
  • I spent a lot of time doing this as well, but tbh it's the least fun part of monkey c development for me. It was satisfying at first to find various tricks for saving memory but at some point it becomes a mechanical grind.

    You are a stingy master. LOL. I am so frustrated that my code is going to exceed the memory limit so I cannot add too many functionalities to WF.As I said before, I use a lot of Chinese bitmap fonts, which seems no way to reduce memory any more.:(

  • You are a stingy master. LOL. I am so frustrated that my code is going to exceed the memory limit so I cannot add too many functionalities to WF.As I said before, I use a lot of Chinese bitmap fonts, which seems no way to reduce memory any more.:(

    Yep, very frustrating :(