I'm doing a significant update on an app that I first released about 18 months ago and I've hit a problem with System 6 devices, so Fenix 6 and similar. I have tried searching for this but not found anything directly addressing it.
This was with SDK 8.4.1 and also with the latest, 9.1.0.
With System 5,
- One instance of the App is created.
- getGlanceView is called once.
- The App instance (or view) makes a web request to fetch a json file.
- The onLayout and onUpdate methods are called.
- When the web request returns, the callback method requests an update.
- onUpdate method is called again and the new data is displayed.
- Closing the app via the debug controls causes a clean exit.
With System 6:
- Three instances are created.
- getGlanceView called for each.
- Each makes the web request.
- onLayout and onUpdate are called on the last instance.
- The web request is only returned to the first instance.
- Web request never calls the callback for the other instances, neither fail or success
- The first instance requests an update but nothing happens.
- Closing the app via debug controls causes a "Failed to terminate app:Timeout"
Here is a minimal reproducible example (can't attach, .mc files are not allowed):
It uses a random number string to identify the app instances.
import Toybox.Application;
import Toybox.System;
import Toybox.Lang;
import Toybox.WatchUi;
import Toybox.Graphics;
function getApp() as mreApp {
return Application.getApp() as mreApp;
}
(:glance)
class mreApp extends Application.AppBase {
var id as String = Math.rand().toString() as String;
function initialize() {
AppBase.initialize();
}
function getInitialView() as [Views] or [Views, InputDelegates] {
System.println("App - getInitialView: "+id);
return [new View()];
}
function getGlanceView() as [ GlanceView ] or [ GlanceView, GlanceViewDelegate ] or Null {
System.println("App - getGlanceView: "+id);
//Position C Fetcher code here has same effect as Position A in the glance view - removed for clarity
return[new mreGlanceLiteView(id)];
}
}
(:glance)
class mreGlanceLiteView extends WatchUi.GlanceView {
var id as String;
var fetcher as Fetcher or Null;
function initialize(_id as String) {
GlanceView.initialize();
id = _id;
fetcher = new Fetcher(id);
//Position A
fetcher.fetch(); //<- this request is successful for the first instance only
}
function onLayout(dc as Dc) as Void {
System.println("Glance - onLayout: "+id);
//Position B
//fetcher.fetch();//<- this request never completes (onReceiveStatus is never called)
}
function onUpdate(dc as Dc) as Void {
System.println("Glance - onUpdate: "+id);
}
}
(:glance)
class Fetcher{
var id as String;
function initialize(_id as String) {
id = _id;
}
function fetch() as Void {
System.println("makeWebRequest called: "+id);
Communications.makeWebRequest(
"https://jsonlint.com/datasets/lorem-ipsum.json",
{},
{
:method => Communications.HTTP_REQUEST_METHOD_GET,
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
},
method(:onReceiveStatus));
}
function onReceiveStatus(responseCode as Number , data as Dictionary?) as Void {
if (responseCode == 200) {
System.println("makeWebRequest successful requestUpdate id: "+id);
WatchUi.requestUpdate();
} else {
System.println("makeWebRequest Error: " + responseCode + " id: "+id);
}
}
}Output for system 5 (Forerunner 945):
App - getGlanceView: 1152874090 makeWebRequest called: 1152874090 Glance - onLayout: 1152874090 Glance - onUpdate: 1152874090 makeWebRequest successful requestUpdate id: 1152874090 Glance - onUpdate: 1152874090
Output for system 6 (Fenix 6):
App - getGlanceView: 1152873265 makeWebRequest called: 1152873265 App - getGlanceView: 1252220708 makeWebRequest called: 1252220708 App - getGlanceView: 1956668138 makeWebRequest called: 1956668138 Glance - onLayout: 1956668138 Glance - onUpdate: 1956668138 makeWebRequest successful requestUpdate id: 1152873265 Failed to terminate app: Timeout
To be clear, the three instances would not be a problem if it the glance just had to draw something. The issue is that the instance that makes the web request is different to the instance that draws the view so there is no visual update. I tried calling the webrequest within onLayout, hence skipping the first 2 instances, but the callback is never called. On system 5, the web request in onLayout works fine.
My question is, is this a bug in the simulator or is this actually how system 6 devices behave? If it is how the device works, is there a workaround to get the 3rd instance to update the display from the web request callback on the first instance?
I don't remember having this problem in the previous round of development but maybe I missed it. I should add, the main app works normally and I haven't noticed any similar issues. In the actual app, the fetched json data is persisted in storage and the main app uses is without issue.
Also, at this stage, with memory constraints, I have basically 3 separate code bases, system 3 and 4 work fine because there are no glances, system 5 and 6 share a code base but work differently as described. System 7 and 8 do significantly more and work fine with no problems in glances or the main app.