Feasibility of Including ~600 SVG Images in Connect IQ App

I'm developing my first Connect IQ app and looking for some guidance on handling a large number of images efficiently.

The app is designed to display a sequence of SVG images — potentially up to around 600 in total (each ranging from 2KB to 20KB). Currently, I'm listing all the images in drawables.xml and assigning the Rex.Drawable.ImageIds to arrays that users can scroll through.

Here's the relevant snippet for how I'm currently displaying each frame:

bmpId = frames[_frameIndex];
_curImage = null;
_curImage = WatchUi.loadResource(bmpId);
dc.drawBitmap(0, 0, _curImage);

I've tested the app successfully with 60 images so far, but before I scale up, I have a few questions:

  • Are all images loaded into memory at app start, or are they loaded on demand?

  • Is it technically feasible to include around 600 images in a Connect IQ app?

  • Are there best practices or optimizations I should consider to handle this more efficiently?

Any insights or suggestions would be much appreciated. Thanks!

  • 1. svg is converted to pixel format during compilation

    2. adding lot of files (bytes) is OK, it'll take more time for users to download and occupy more on their device, but it should probably work

    3. Not sure about drawables, but with strings there's a 255 limit. If there's no such limit for drawables, then it shouldn't matter how many you have.

    4. You load them with loadResource. Just don't hold on to their reference for long. Of course you'll only be able to keep a few of them in the memory at a time.

    But unless your app is called Depleate Battery Fast I would not recommend doing that... Loading and rendering 600 images will just kill the battery IMHO.

    What exactly are you trying to do? Display a movie?

  • I'm doing a step-by-step guide where the user can flip the guide image if desired. Initially I was using AffineTransform to flip with drawBitmap2 but not all devices supported that.  Now I plan to provide both flipped and unflipped images, doubling the amount I had originally intended.

    4. Does setting _curImage to null take care of that, or are more steps required to ensure the reference is released ?

    The guides are broken up into roughly 30 images, I suspect in a given session a user will only interact with one or two guides. They will page through and flip (if desired) manually.

    It sounds like I should be ok to proceed though. I just didn't want to invest too much time in illustrations if it was a non-starter. I appreciate the help!

  • #3 - Isn't the 255 limit in strings for older watches only?

    Which makes me ask a relevant question for the OP - are you aiming at the more recent watches only? As this has more likelihood of succeeding

  • Still getting used to the message moderation queue. I have a reply pending, I think.

    I am also wondering it I can work from the premise of "If it works on the simulator it'll work on the device". As such I'm trying to use broadly supported APIs and target as many devices as possible.

    I've been looking into unit tests. Are there any nice online examples of E2E tests? Perhaps I can run a series of user actions through all devices.

  • 4. You load them with loadResource. Just don't hold on to their reference for long. Of course you'll only be able to keep a few of them in the memory at a time.

    To clarify this, on CIQ 4 devices, loadResource will load resources into the shared graphics pool, not your app's memory.

    e.g. pre-CIQ 4:

    var b = loadResource(Rez.Drawables.someBitmap); // b is a Bitmap which is loaded into app memory and freed when there are no more references to the object

    CIQ 4 and higher:

    var b = loadResource(Rez.Drawables.someBitmap); // b is a BitmapReference which points to bitmap that's loaded into the shared graphics pool, which is automatically managed by the system. If you want to lock the resource in the graphics pool, you can call b.get()

    [https://developer.garmin.com/connect-iq/core-topics/graphics/#graphicspool]

    Some devs have found that the graphics pool may actually be a disadvantage when loading large numbers of bitmaps simultaneously (I don't have any experience with this myself):

    [https://forums.garmin.com/developer/connect-iq/f/discussion/328086/how-to-force-system-to-not-using-graphics-pool]

  • _curImage = WatchUi.loadResource(bmpId);
    dc.drawBitmap(0, 0, _curImage);

    If you are loading bitmaps in onUpdate and onUpdate is firing once per second, this will be a huge CPU/battery drain on the device, as storage is extremely slow. Not only may the user notice the battery drain, but the user may also notice general sluggishness during updates (e.g. the watch may be slow to respond to button presses).

    iirc, Garmin tends to suggest loading resources in other functions, like onLayout() or onShow(), which aren't being called constantly.

    Ofc it may be unavoidable to load images regularly since you have 600, but maybe you could try loading 10 at a time, once every 10 seconds / updates, for example?

    EDIT: nvm, what I said above doesn't really make much sense when it comes to a guide that the user manually flips through with touch gestures or button presses..

    flocsy's response is a lot more relevant

    [I downvoted this comment myself]

  • Ah, IMHO it should work. You can test if it's OK to only load the image when the user swipes. If it's too slow, then maybe pre-load the next image (and keep also a reference to the previous in case the user can also swipe back). It shouldn't be a problem to keep 3 in the memory and it should be fast enough for manual user swipes.