Rigel Group

They shoot Yaks, don't they?

Transparently Cache Network Calls in Titanium

Typically, when you are building a mobile app with Titanium, you are grabbing data from the web via RSS/Atom/etc or various APIs, and displaying them to the user. And of course, when developing for mobile clients, you can never take the network for granted. So a common pattern we use is to always cache the results of network requests locally, so in the event of a network glitch or even “airplane mode”, we still have some (stale) data to show to the user. We have packaged this functionality up into a CoffeeScript snippet here.

Basically, it is a wrapper around the standard Titanium.Network.HTTPClient API, except that we cache the results of each request in a local SQLite database table, and use that for subsequent requests until the cached record expires. The cache key is a hash of the full URL (plus any data parameters for POSTs).

For an example (written in CoffeeScript), we can create a new instance of the class to connect to the CNN RSS news feeds:

1
2
3
4
5
6
7
8
9
10
  Ti.include("HTTPClientWithCache.js")
  cnn = new root.HTTPClientWithCache({
    baseURL: "http://rss.cnn.com/rss",
    retryCount: 2,
    cacheSeconds: 60,
    onload: (response) ->
      Ti.API.debug("Response Data: #{response.responseText}")
      Ti.API.debug("Is this cached data?: #{response.cached}")
      Ti.API.debug("Cached at: #{response.cached_at}")
  })

Each time we want to make the request, we say:

1
  cnn.get({url: "/cnn_topstories.rss"})

The response will either come from the cache, if it has not expired, or from cnn.com. Because we set the retryCount property to 2, if the first attempt to fetch the data over the network fails (meaning any HTTP status code > 400) it will automatically try again a second time. If that fails, then it will respond with the most recent version available in the cache, or null if nothing exists in the cache. The response object also has a cached property of true for anything served out of the cache, and a cached_at property of the timestamp the record was cached.

You can use the same object to make calls to other URLs as well, like so:

1
  cnn.get({url: "/cnn_us.rss"})

If you need to pass parameters (like for pagination) you can say:

1
  cnn.get({url: "/cnn_us.rss?page=1"})

To POST data to a URL, do this:

1
  cnn.post({url: "/story/19912/edit", data: {param1: "value1", param2: "value2"}})

To manually prune the cache, you can call the prune_cache method, and anything older than seconds will be deleted from the cache. For example, to remove anything older than 1 day (86,400 seconds) you would say this:

1
  cnn.prune_cache(86400)

To completely clear the cache of every single entry, you can do this:

1
  cnn.prune_cache(0)

The code is on GitHub as a gist here. For pointers on how to build Titanium apps using the incredible CoffeeScript instead of Javascript, see our previous blog post here.