Complete
over 4 years ago

Not a bug.

Weather.getCurrentConditions().attribute crashes when data is not available SDK 3.2.1

I am using the brand new shiny SDK 3.2.1 weather feature which I absolutely love. However, I was dismayed when my watch face crashed in the simulator after I unchecked the "Weather Data Available" box in the settings. I was calling Weather.getCurrentConditions().temperature, and I got an unexpected type value error. When I called Weather.getCurrentConditions() instead, it recognized it as a null value and I could use an if statement to work around it. I have not tested the other weather functions or attributes.

Can the attributes for the weather functions get null values when data is not available? Thanks

Former Member
Former Member
  • "although I am not following your use of makeTemp."

    makeTemp is just a helper function that does things like C to F conversion. 

  • The documentation for Weather.getCurrentConditions() explicitly says that it may return null if no data is available. The API is behaving as advertised, the issue is with your code.

    This is your code from line 211:

    if (Weather.getCurrentConditions().temperature == null) {
    

    The problem is that Weather.getCurrentConditions() can return null. If it does, your code evaluates to this...

    if (null.temperature == null) {
    

    The null value doesn't have any member data (no temperature field), so you can expect that to produce an error, which it does.

    If you want to do this correctly (and efficiently), you want to check for null in places where it is possible and avoid multiple calls to getCurrentConditions. Something like this:

    var currentConditions = Weather.getCurrentConditions();
    if (currentConditions != null) {
        // current weather conditions are available
        // it is safe to access the temperature field
    
        var currentTemperature = currentConditions.temperature;
        if (currentTemperature != null) {
            // we have a valid temperature in `currentTemperature`
            mCurrentTemperature = currentTemperature.toString();
        } else {
            // no temperature data
            mCurrentTemperature = "--";
        }
    } else {
      // no current weather conditions
      mCurrentTemperature = "-";
    }

    If you're targeting only devices with 3.2.0 support, you don't need to do the has check mentioned by . If you are going to support older devices, you must take care to never access the Weather module without checking that it exists with a has check.

    class MyWatchFaceView extends WatchUi.WatchFace
    {
        var mHasWeather;
        var mTimer;
    
        function initialize() {
            WatchFace.initialize();
    
            mHasWeather = (Toybox has :Weather);
        }
        
        function onShow() {
            var millisecondsPerMinute = 60 * 1000;
            var weatherUpdateIntervalMinutes = 75;
            mTimer = new Timer.Timer(self.method(:onTimer), weatherUpdateIntervalMinutes * millisecondsPerMinute, true);
        }
        
        hidden var mCurrentTemperature;
        
        function onTimer() {
        
            if (mHasWeather) {
                // use the code above in here to set mCurrentTemperature
                // to a string based on weather and temperature availability
            }
        }
        
        function onUpdate(dc) {
            // ...
    
            if (mCurrentTemperature != null) {
                dc.drawText(x, y, font, mCurrentTemperature, justify);
            } else {
                // onTimer has not executed yet, so we don't have a temp
            }
        }
    }

  • Former Member
    Former Member over 4 years ago in reply to jim_m_58

    Hi Jim,

    Thanks for the tip. I have this function in a separate Util.mc file, but in this case the strings are so simple I can just use "C" and "F" instead of calling resources.

    Since temperature is the only thing I need, at first I did not even think about using the broader function Weather.getCurrentConditions() by itself. But after reading the API and seeing that it should return null, I decided to try it.

    This is the error I get in the console:

    Error: Unexpected Type Error
    Details: Failed invoking <symbol>
    Stack:
    - getTemperature() at C:\...\source\Util.mc:211 0x1000071d

    - ...

    - ...

    After I this code: 

    The line reference is the same line as the if statement.

  • Just a general comment, but some of the stuff you're doing each time the function is called can just be done once when the app starts. No need to do the loadResource each time for example.  That's something that hits the file system, so can be expensive.

  • "temp" in my code is just short for temperature.  It's the sting I'll be displaying.

    You shouldn't need to null check Weather.getCurrentConditions().temperature

    What is the error you see, and which line is referenced?