Delayed onReceive Callback and UI Blocking After Web Request with Large JSON

After recently dealing with Storage limits when handling large JSON responses from web requests, I’ve encountered another related issue.

When sending a request using Communications.makeWebRequest, the app continues to process other events until the response is received. In my case, these requests are used to update already displayed data, and the user can interact with the app while updates are processed. To avoid blocking the UI, I handle the response inside a task queue, which chunks the processing of the large JSON—this part works well on my end.

However, I’ve observed a problem with the processing that occurs before my callback is triggered. In most cases, even with large (but within-limit) JSON responses, the pre-callback processing is fast enough not to affect the user experience. But occasionally, the delay before the callback is invoked spikes to 4–5 seconds, during which the UI becomes unresponsive.

Here’s a log excerpt from one instance where this occurs:

28.5.2025 15:01:14: TaskQueue: start executing tasks (12 queued)
28.5.2025 15:01:14: SitemapRequest.makeRequest (#5)
28.5.2025 15:01:14: TaskQueue: stop executing tasks after 46ms (0 remaining)
28.5.2025 15:01:18: SitemapRequest.onReceive: start (#5)
28.5.2025 15:01:18: SitemapRequest.onReceive: end

There is a 4-second delay between makeRequest and the start of onReceive, which is not typical. The request is sent to a local server, so network latency is not a factor. Also, if the delay were due to a slow response, I would expect the app not to block.

For comparison, here’s a log from a typical case—same server, same JSON response:

29.5.2025 11:25:47: TaskQueue: start executing tasks (3 queued)
29.5.2025 11:25:47: SitemapRequest.makeRequest (#7)
29.5.2025 11:25:47: TaskQueue: stop executing tasks after 62ms (0 remaining)
29.5.2025 11:25:47: SitemapRequest.onReceive: start (#7)
29.5.2025 11:25:47: SitemapRequest.onReceive: end

I’m trying to understand what might be causing the API’s internal processing—between the network response and the invocation of the callback—to occasionally take significantly longer, blocking the app during that time.

Has anyone else experienced similar issues with large JSON responses and delayed callbacks in makeWebRequest? Any insights or workarounds would be appreciated.

  • One thing I forgot to mention: this was observed on a physical Epix 2 Pro. I am not able to reproduce it in the simulator. 

  • I did "feel" like this happens also on my fr965. Obviously we're talking about different api, different structure of json, and also different other things are going on on the watch (app vs data field, what other data fields are present, etc...)

    I can't say if the downloading of the response takes time, or the deserialization of the response.

  • I’ve now observed the issue occurring in the simulator as well. I’ll investigate it further and will post my findings here.

  • Regarding the simulator, I’m not sure whether what I’m observing is actually related to the issue. I did write some test code to approximate the time spent in pre-processing between receiving the web response and the invocation of the onReceive callback. The test works by chaining timed tasks: it measures the time elapsed since makeWebRequest() was called, and then again inside onReceive(). The time between the last task execution and entry into onReceive() is assumed to represent the internal pre-processing time.

    Typically, this delay is around 50–80 ms in the simulator, with occasional spikes up to 200–350 ms.

    On a real device, however, the delay is significantly longer—often around 3 to 4 seconds.

    This might simply reflect the faster execution environment of the simulator, but it could also point to entirely different behavior or overhead on the actual device.

    I’ll continue running more tests on hardware to gather additional data. That said, I suspect this may be something I—and ultimately, my users—will have to live with. It’s unlikely to be a simple bug; more likely, it’s tied to how the API internally handles large responses, possibly influenced by other background operations or system-level constraints.

  • The time between making the request and getting the data will be faster in the sim, even with a small amount of data.

    3 or 4 seconds on a real device doesn't strike me a a long time.  Back when I started doing makeWebRequests (actually at the time, makeJsonRequests) you'd see longer - say 10 seconds or longer if there was an issue....

    You won't see the same times on a real device as you see in the sim.

  • 3 or 4 seconds on a real device doesn't strike me a a long time.

    Most requests are processed quicker; the 3–4 second delay only occurs intermittently—every few requests. The real issue is that this delay doesn’t happen while waiting for the response (during which the app can still handle other events like user input), but rather during the pre-processing of the response before the callback is invoked. This stage blocks the app’s UI, making it unresponsive during that time.

  • I thought that there is a setting in the simulator where you can make the internet connection slower. But I couldn't find it now. Probably it was in the android simulator :) But it would be a good idea for Garmin to add this.

  • I thought that there is a setting in the simulator where you can make the internet connection slower. But I couldn't find it now. Probably it was in the android simulator :) But it would be a good idea for Garmin to add this.

    I think in this case it is less about the Internet speed and more about the processing speed. Since the time in question is lost in the pre-processing of the response, between its receival and the invokation of the callback.

  • I'm sorry but I think I don't understand how you divide the time between the call of makeWebRequest and the call of the callback. To me it seems like it's a black box. I don't know how is it possible to put a line when the downloading of the bits finished and the deserislization starts

  • I'm sorry but I think I don't understand how you divide the time between the call of makeWebRequest and the call of the callback. To me it seems like it's a black box. I don't know how is it possible to put a line when the downloading of the bits finished and the deserislization starts

    I'm not sure if this is the correct terminology, but let's assume the CIQ engine maintains an event queue that handles things like user input, timer events, and web request responses.

    Here's my thinking: after calling makeWebRequest, control is returned to the app, and the system continues processing other events until the response arrives—at which point it triggers a new event for processing the response and invoking onReceive.

    To analyze the timing, I record the time of the makeWebRequest call using System.getTimer(). Then, I schedule recurring 50ms timer events, each of which logs the elapsed time since the request was made. When onReceive is called, I measure the time again. The difference between the last timer event and the onReceive time represents the time spent in the pre-processing phase after the response has arrived, before the app is notified.

    Of course, this method only provides 50ms granularity, so it’s not highly precise—but it seems accurate enough for the purpose of investigating this issue.

    That said, you're right that it's still unclear what exactly happens during this pre-processing phase. For example, it would be interesting to know whether the transfer of data from the phone to the watch occurs during that time, or if it already happens earlier, while the app still has control and can continue processing other events.

    I haven’t yet run this test on the actual device, but I plan to do that today.