Hello!
I am trying to write my very fist widget for my Garmin watch. I encountered an issue with ViewLoop that causes my application to crash. For now I am uncertain if I am doing something wrong. The sample that makes use of ViewLoop (Primates) is not straightforward in my opinion, so it's hard to say. I hope a member of the community can point me to any mistake I made so I can resolve this quickly.
I don't encounter this issue when running the Primates sample on my watch, but that is not a Widget (it's an app) and the implementation makes it unclear to know whether or not it even uses ViewLoop when ran on my watch, or an alternative View. (See the getInitialView function in the Primates sample, file: PrimatesApp.mc).
According to the ViewLoop documentation (https://developer.garmin.com/connect-iq/api-docs/Toybox/WatchUi/ViewLoop.html) my watch is supported so I assume my watch uses the ViewLoop implementation and not the alternative implementation present in that sample. My Watch is up-to-date according to Express.
To replicate the issue consistently, I created a minimal widget with just a LoopView and 5 demo views, implemented in the way that I understand from the documentation and the Primates sample, and ran it. The issues seem to persist.
My minimal widget code (in one file for ease of use, obviously in a real codebase this would be split up for clarity) pasted here:
import Toybox.Application; import Toybox.Lang; import Toybox.WatchUi; import Toybox.Graphics; class DemoViewLoopIssueApp extends Application.AppBase { function initialize() { AppBase.initialize(); } // onStart() is called on application start up function onStart(state as Dictionary?) as Void { } // onStop() is called when your application is exiting function onStop(state as Dictionary?) as Void { } // Return the initial view of your application here function getInitialView() as [Views] or [Views, InputDelegates] { var myViewLoop = new ViewLoop(new MyViewLoopFactory(), null); return [ myViewLoop, new ViewLoopDelegate(myViewLoop) ]; } } function getApp() as DemoViewLoopIssueApp { return Application.getApp() as DemoViewLoopIssueApp; } class MyViewLoopFactory extends ViewLoopFactory { private var _views as Array<View> = [ new MySimpleView("View 1"), new MySimpleView("View 2"), new MySimpleView("View 3"), new MySimpleView("View 4"), new MySimpleView("View 5") ]; function initialize() { ViewLoopFactory.initialize(); } public function getSize() { return _views.size(); } public function getView(index as Number) { return [ _views[index], new BehaviorDelegate() ]; } } class MySimpleView extends View { private var _message as String?; function initialize(message as String) { View.initialize(); _message = message; } /* function onLayout(dc as Dc) { } */ function onShow() { } function onUpdate(dc as Dc) { View.onUpdate(dc); dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.drawText(100, 100, Graphics.FONT_MEDIUM, _message, Graphics.TEXT_JUSTIFY_RIGHT); } function onHide() { } }
The issue: When the widget is opened (so not the glance view, but really "into" the widget by) and times out or is "popped" to the watchface (e.g., by holding the back button for a second or two) and then re-opened, the widget crashes.
Did I implement the ViewLoop incorrectly? Or is there a way for me to verify what implementation my watch is using from the Primates sample (by editing it perhaps)? I am beginning to believe my watch doesn't actually fully support ViewLoop even though the documentation page states it does.
I attached my minimal widget code as a zip file for anyone who wants to test and run on their device too. The issue cannot be replicated in the simulator. In my code I only marked my watch as device, so if you want to test on another device you will have to edit manifest.xml.