One of the aspects of the Pointillism mobile app that was recently released was that users were expected to use the game while in remote areas. Remote areas often mean that data service is limited or just plain not available at all, and that can wreck havoc for game participants waiting for data to load. There are two schools of thought in how to approach this problem.
One is to pre-load all the content that the game would or could ever use. This means that you either package all the data / images with your app, or you force the user to download this data when they launch the app. The advantage of this method is that the user can pretty much be completely offline after that point and still get the entire experience of the game. The disadvantage of this, of course is that then you front-load ALL of your content. If the user is on EDGE (or worse!), this would mean they would be downloading a LOT more data than they may need to in addition to making your app use more space on the end devices.
The other method is to setup some sort of caching strategy. This requires the user to be online at least for the initial exploration of each section of your app, but after that, the data is stored on their device. This can be problemsome if they are offline, of course, but depending on the game, this may not be an issue. In a cached mode, the user will attempt to read from disc and return that data WHILE making the call to the service in order to pull down the latest data. To the end user, this becomes transparent. Updating cached data is also routine as all if you have to do is invalidate the cache to get that bit of new data.
In Pointillism, we worry about two types of data — lists of data (Collections, Arrays, Vectors, etc.), and user-submitted images. Our goal is to cache both.
Luckily, Caching the images was super easy. Dan Florio (PolyGeek) wrote a component known as the ImageGate which houses an Image component and a caching mechanism. Using his component is as simple as substituting the <s:Image> in your MXML or ActionScript with his component, and boom — your images are cached as soon as they are viewed. I did make a few tweaks to his component and posted it on my space over at Apache. I substituted the Image component with a BitmapImage for speed, and added a small patch to cache the images in the proper location on iOS devices.
Caching lists of stuff was not much harder. AIR has a built-in “write to disc” functionality known as SharedObjects. SharedObjects started as an alternative to cookies in the browser, but within AIR allow us to store variables for long-term storage. In my case, I choose to store data that came back from the server as a SharedObject every time we got some data back. This turned out to be a good strategy as it allowed us to show old data immediately and update it with current data once it came in. Our data didn’t change /that/ often, so it might update at most every day or so.
One of our data manager’s constructor looked like this :
so = SharedObject.getLocal("org.pointi.cache");
if (so.data.pointsList == null)
so.data.pointsList = new Array();
When we got our data back from our server, we did this :
so.data.pointsList[curHuntID] = event.result as ArrayCollection;
And finally, when we wanted to read back the data, this is all we had to do (pointsList is the variable that was sent to our calling components):
ro.getPointList(huntID, userID); //call the remote function on the server
if (so.data.pointsList[huntID] != null)
pointsList = so.data.pointsList[huntID] as ArrayCollection;
Pretty simple, eh? We did similar setups for all of our data lists, and also implemented some caching for outgoing data (like when the user successfully checked into a location), so we could keep the server in sync with the client.