Improve App Performance- Speed Optimizations
This guest post was written by Tomáš Slavíček, a developer from Prague, Europe. You can learn more about him on Twitter or view additional watch faces byTomáš on the Connect IQ Store.
So your application finally fits into the memory, but it is still slow. Or some users are reporting that it does not run well on their device. How do you measure this? First, you need to test it on a real device. Results from the simulator will not make any sense; you will always see 0 milliseconds or some other very low value.
You can use the Timer object. It is very simple to use; you can just write a few lines of code and print the measured output into the log file:
To be able to see the log, you need to create an empty text file on the device in the Garmin/Apps/Logs folder with the same name as the application:
Now you can start measuring the initialize, onLayout and onUpdate methods and see where the problem is and what can be optimized. The whole initialization process should be lower than 300 milliseconds, so the application still feels fast and fluid.
Some devices are slower, and some are faster. The Tree benchmark that is available to download on Connect IQ Store is very useful for developers. In the application description, you can see the list of devices and how they perform (higher number is better). For example, the vívoactive HR is slightly better than fēnix 5, because it has a lower display resolution and it needs to draw less pixels.
Other speed optimizations
There are some other useful tips for speed optimization:
- Accessing global variables in Monkey C language is slow. In fact, it is about eight times faster to use the local variable than a global one. You can measure it by yourself, but sometimes it is faster to copy the global array of values into a local variable in the method, then read these values in for cycle, and copy them back into the global variable.
- If you have a lot of classes, interfaces, methods and other objects, the app can be also slower than if you have everything written in one file.
- And once again, if you can pre-calculate any values and save them for later, it will be faster to just load them later from the storage than calculating again. If you need to draw 12 images around the watch face, you can pre-calculate the sine and cosine of each angle, or even the final positions of these images.
- Do not forget to remove these System.println() calls in the final release
You can watch the talk Effective Monkey C from the Garmin Connect IQ summit 2017 for other useful tips. Here is another list of performance DOs and DONTs. This thread about Monkey C compiler is also interesting to read.
When you draw a more complicated watch face, or if you want it to refresh every second (on SDK 2.3 devices), you might need more optimizations.
You can draw one part of the application into a bitmap. This will be drawn just once at start-up (or just once per minute). Then you can add an overlay text every second over it. This will take more memory, because you need to keep the bitmap in the memory, but it will be faster. You can also specify a limited color palette of the bitmap, for example just 4 colors, to keep the memory as low as possible. You can see the 1Hz watch faces tutorial on Garmin forums.
You do not need to use the background bitmap. If you do not call the clean() method in onUpdate, the contents of the screen will be still displayed even the subsequent onUpdate calls. You can just update the small part of the screen that you need. For example, you can draw a black rectangle over the text and then update the text.
You just need to be sure to clean the buffer every onLayout, onShow and onExitSleep methods, otherwise your content will be overwritten with parts of the watches’ system: