Maintaining an offline data cache

Currently, the TripLog app's MainViewModel calls the TripLogApiDataService to get its data directly from the live API. As mentioned at the beginning of this chapter, in the event of little or no connectivity, the TripLog app will fail to display any log entries. With a few minor modifications to the MainViewModel, we can set it up to use the Akavache library to retrieve log entries from a local cache, and also to refresh that cache with any changes in the dataset once a connection with a live API succeeds.

First, update the MainViewModel constructor to require an instance of Akavache.IBlobCache, which will be injected via our Ninject implementation from Chapter 4, Platform-Specific Services and Dependency Injection:

readonly IBlobCache _cache;

// ...

public MainViewModel(INavService navService,
ITripLogDataService tripLogService,
IBlobCache cache)
: base (navService)
{
_tripLogService = tripLogService;
_cache = cache;

LogEntries = new ObservableCollection<TripLogEntry> ();
}

Next, we will need to modify the logic in the LoadEntries method to tie into the local offline cache. To do this, we will leverage an extension method in Akavache called GetAndFetchLatest. This method actually performs two functions. First, it immediately returns cached data, given a specific key (in our case, entries). Secondly, it makes a call to the API based on the given Func<> and updates the cache for the given key. Since it is performing two functions, it will ultimately return twice. In order to handle this, and because it is returning an IObservable, we can use the Subscribe extension method to handle each return as it occurs. In the Subscribe extension method, we will update the LogEntries ObservableCollection property on the MainViewModel based on what is either returned from the cache or from the subsequent API call, if successful:

public override async Task Init()
{
LoadEntries();
}

void LoadEntries()
{
if (IsBusy)
{
return;
}

IsBusy = true;

try
{
// Load from local cache and then immediately load from API
_cache.GetAndFetchLatest("entries", async ()
=> await _tripLogService.GetEntriesAsync())

.Subscribe(entries
=> LogEntries = new ObservableCollection<TripLogEntry>(entries));

}
finally
{
IsBusy = false;
}
}

In the preceding code, notice that, because we're calling GetAndFetchLatest and using the Subscribe method, the LoadEntries method is no longer async, so ensure that you update the RefreshCommand execution Action as well.

The first time the app is launched with this code, the cache will be populated. On any subsequent launches of the app, you will notice that data appears immediately as the view is constructed. If you add an item to the backend service database and then launch the app again, you will notice that the new item falls into place after a couple of seconds.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.126.211