I’m happy to say that I made a lot of progress on our team project over the past week or so. To review, “Doge Parks” is a mobile-only application that we’re working on for finding nearby dog parks and connecting with other dog owners. In essence, it’s sort of like a combination of Google Maps and Yelp. While there are obviously similar apps out there, we hope that “Doge Parks” can differentiate itself by fostering a strong community of dog owners who share park feedback and reviews amongst each other.
This sprint, our group decided to use the Google Maps API for obtaining map-related information. Getting a Google Map to display in our app was easy enough–I simply had to install all of the required dependencies in our source code, register for an API key, and add a little bit of code. Allowing the user to change their location and then updating the Google Map was difficult, however. I guess I’m still a little rusty on Flutter’s syntax and state management flow because it took a day of troubleshooting for me to realize that I wasn’t handling asynchronous functions appropriately.
In most functions that we write, it’s fairly easy to visualize the order of how lines of code are executed. Take the Python snippet below, for instance:
def my_function(
):
a = 1
b = 2
return a + b
We can tell from a quick glance that the function 1) initializes variable a
to 1
, 2) initializes variable b
to 2
, and 3) returns the sum of variables a
and b
. With Dart/Flutter, it can become much more difficult to track this flow of execution, especially if you’re using a lot of different asynchronous functions. In Flutter, these functions return Future objects. You can think of Future objects like empty boxes, waiting to be filled from some asynchronous operation. The issue I ran into was something similar to the following:
doSomething
();
doSomethingAfter();
In this example, the function doSomething()
is an asynchronous function that requests information from the API and then stores that information into variables. If doSomething()
was a synchronous function (perhaps we used the await
keyword), it would finish running first and then doSomethingAfter()
would run. But that’s not the case here. Because it’s asynchronous, doSomething()
runs in the background while waiting for the API request to be completed. During that time, doSomethingAfter()
runs and tries to retrieve data from the shared variables, but that data has not yet been updated by doSomething()
. As a result, our Google Map wasn’t able to update to it’s new latitude and longitude when a new location was selected. In fact, most of the time, the app crashed because of Dart’s null safety.
The solution ended up being really simple. I basically just had to call doSomethingAfter()
in the last line of doSomething()
, once the API request was completed. With this, I ensured that doSomethingAfter()
would always have access to the updated variable values.