Background operation - exit functionality

Former Member
Former Member
As I don't get reliable results from tests - maybe somebody could clarify that? …

I have an operation called in the background - let say - every hour.
Sometimes this operation return NULL and sometimes it returns real data.

Imagine following scenario -

time: 1:00
background -> return NULL
time 2:00
background -> returns DATA
time 3:00
background -> returns NULL

time 3:30
User starts the widget - it automatically retrieve received data through onBackgroundData function
WHAT will receive this function - NULL (as last received) from 3:00 OR DATA from 2:00 ?

That's not really clarified in documentation...

Thanks!
  • Can you post your background code? A null could be valid based on what you are doing.

    You'll see a null if, for example, you end up with something like:

    var data=null;
    .....
    Background.exit(data);
  • Former Member
    Former Member
    Jim,

    The question is slightly different (sorry to not to be clear)…

    Lets say - my code (pseudo-code) is as follow:


    class BackgroundProcess extends System.ServiceDelegate {
    function onTemporalEvent() {
    …
    if( some_condition ) {
    //no data to pass
    Background.exit(null);
    } else {
    //there are data to be passed - e.g. location is known from Toybox.Activity.getActivityInfo() or from last activity stored in Storage
    …
    //get data from external service
    Comm.makeWebRequest( …. )

    //of course this response is taken in the other function - e.g. onReceive - but I'm just simplifying things
    Background.exit(response);
    }
    }

    And the big question is - does Background.exit(null) removes data from previous Background.exit(response) ?
    I can imagine - there is a kind of buffer to pass data from the background process to the main process and not clear is whether this buffer is cleared by calling Background.exit(null)


    onTemporalEvent is called every 1h
    first call - returned response
    second call - returned null (as for some reason - there were no data to pass)

    and now user starts widget - therefore immediately onBackgroundData is called:

    class MyLovelyApp extends App.AppBase {
    ....
    function onBackgroundData(data) {
    }
    }

    What will be in data parameter? NULL or response?

    Hopefully now my question is clear :)




  • Ok, in the event that the background has run multiple times without the widget being run, the widget will only see what was last returned by default.

    So if
    widget runs
    background runs, exits with data1
    background runs, exits with data2
    background runs, exits with null
    widget runs, gets null

    the widget ONLY sees the result of the last run of the background - a null.

    The way to handle multiple runs of the background without the widget running is to use getBackgroundData in the background process. See whats already queued for the widget and append to that.

    So, in the above case

    widget runs
    background runs, getBackgroundData=null, exits with data1
    background runs, getBackgroundData=data1, exits with data1+data2
    background runs, getBackgroundData=data1+data2, exits with data1+data2 (or possibly data1+data2+null)
    widget runs, gets data1+data2 (or data1+data2+null)

    The one thing you need to consider is if what you get from getBackgroundData should be used. For example, if the widget hasn't run for 24 hours, do you need data more than 12 hrs old? You'll want to trim getBackgroundData to what's useful to the widget, other wise, you could queue up days worth of data, run out of memory, etc.

    In one of my widgets with backgrounding for example, I get a value every 5 minutes, but the widget only cares about the last 4hrs, so in that case, I trim what I get from getBackgroundData, so I return at most 48 values, even if the widget hasn't run in a day.

    Another thing to note is the background might not run when you expect it to. Due to availabe resources, it might not run for a while. In the example I posted, if a watch-app is running for 30 minutes, the background doesn't run for that 30 minutes, so the newest data the widget sees is 30 minutes old.
  • Former Member
    Former Member
    Jim,

    Too my observation - you are right - if last call returned NULL - then widget will receive NULL too... BUT - to my understanding (English is NOT my primary language) this is inconsistent with documentation :


    backgroundData (Toybox::Lang::Object) —
    The object to pass to the main process's AppBase.onBackgroundData() method. If no data should be passed to the main process, null may be specified.


    My understanding was - no data passed, so previously passed data are preserved. Seems to be wrong understanding. GARMIN - could you update above sentence to have it clearly stated? :)

    I'd love to have a possibility to exit from the background process without erasing previously stored data. It comes from the logic of my widget...
    Thanks for the other notes - yep, I'm aware that run time of background is not exact.
  • You could simplify what you do, based on what you need, so in the above, it could be:

    widget runs
    background runs, getBackgroundData=null, exits with data1
    background runs, getBackgroundData=data1, exits with data2
    background runs, getBackgroundData=data2, exits data2
    widget runs, gets data2

    That way you'd not need to do any trimming.

    For the 3rd run of the background and a null, you can also just not call Background.exit(), but that means the background would still run for 30 seconds. - it wouldn't be doing anything, but could be delaying other background evets waiting to run.
  • Former Member
    Former Member
    This is a good question. This scenario is probably not clearly documented.

    Jim, did you test this? I took a quick look, and it does not appear that Background.exit(null) will overwrite existing data that has been passed to Background.exit(). We will need to evaluate this, as this behavior would make it impossible to remove data if that behavior was desired. (You could of course do something like Background.exit(0)).

    You really shouldn't skip exiting the background process and let the timer expire. This could interfere with a users other background processes. If we do classify this behavior as a bug and change it, you will probably be able to avoid overwriting your old data if desired by calling System.exit() instead of Background.exit().
  • Brian, I didn't specifically test this, but I'd expect Background.exit(null) to wipe out whatever is queued up, because as you said, if it didn't, you couldn't remove queued data by just returning null. (I made an assumption :) ).

    I'll test it out later.

    And like you said, NOT calling Background.exit() isn't the way to do this, as it would block other background processes longer than needed. I always call Background.exit() in a background process. if a null was detected, I'd just return what I got from getBackgroundData() in this case (and that could be null!)
  • Ok Brian, I tested this. Your "quick look at the code" was correct. (I'm using an f5 with the 10.52 beta FW). If Background.exit(null) is called, it does not reset the data in getBackgroundData, and if the widget runs following that, it sees what was in getBackgroundData, and not the null. But (and this will take some changes to my test widget), if getBackgroundData is null, the widget may see a null in onBackgroundData. What's expected? A null, or no call to onBackgroundData at all? I'll try that later today...

    It does seem to me that Background.exit(null) should clear what's queued though, though I'm not sure I can think of a use case for that! :D

    In my stuff, I return either data or an error to indicate why there was no data (phone not connected, etc), and can't think of a case where I return "null" in my apps.
  • Former Member
    Former Member
    If you need to clear out the data that was previously set, you would need to work around the current behavior by doing something like: Background.exit(0). The foreground app would need to handle receiving 0 in this case.

    I've created a ticket to evaluate this scenario and make a decision on if it will be documented as-is, or classified as a bug and fixed.
  • Former Member
    Former Member
    This was classified as a bug, so we do intend to update the functionality to remove any existing data payload when Background.exit(null) is executed. This should eliminate the call to onBackgroundData(). We will also attempt to clarify the documentation of this case.

    If you do not wish to overwrite old data when exiting, you can fetch the old data with getBackgroundData() and pass it to Background.exit(), or exit the process with System.exit().