Caching and Offline

Caching

Kinvey's Android library provides you with means to utilize caching. This feature can make your app more responsive, and allows you to handle various concerns around network connectivity on a mobile device.

Caching is integrated directly into the AppData API, so any time data is retrieved from Kinvey, the response can optionally be stored locally. You can use a cache policy to determine how AppData should behave when caching data and retrieving it while online.

Cache Policies

  • CachePolicy.NOCACHE - This policy will not use any caching, and will execute every request online.

Use this policy if your application is dependant on data that is shared between multiple users and always needs to be up to date.

  • CachePolicy.CACHEONLY - This policy will only retrieve data from the cache, and will not use any network connection.

Use this policy in combination with another policy, to allow for quick response times without requiring a network connection for specific operations.

  • CachePolicy.CACHEFIRST - This policy will first attempt to retrieve data from the cache. If the data has been cached, it will be returned. If the data does not exist in the cache, the data will be retrieved from Kinvey's Backend and the cache will be updated.

Use this policy if your application can display data that doesn't change very often but you still want local updates.

  • CachePolicy.CACHEFIRST_NOREFRESH - This policy will first attempt to retrieve data from the cache. If the data has been cached, it will be returned. If the data does not exist in the cache, the data will be retrieved from Kinvey's Backend but the cache will not be updated with the new results.

Use this policy if you want to set default results, however if a request is made that cannot return these defaults a live request will be made (without modifying those default values)

  • CachePolicy.NETWORKFIRST - This policy will execute the request on the network, and will store the result in the cache. If the online execution fails, the results will be pulled from the cache.

Use this policy if you application wants the latest data but you still want responsiveness if a connection is lost

  • CachePolicy.BOTH - This policy will first retrieve an element from the cache, and then it will attempt to execute the request on line. This caching policy will make two calls to the KinveyClientCallback, either onSuccess or onFailure for both executing on the cache as well as executing online.

Use this policy if you want more responsiveness without sacrificing the consistency of data with your backend.

Set Up AppData Cache

By default, AppData caching policy is CachePolicy.NOCACHE. Setting the cache policy to anything else requires only one line of code.

import com.kinvey.java.cache.InMemoryLRUCache;
import com.kinvey.java.cache.CachePolicy;

//...

AsyncAppData<EventEntity> myevents = kinveyClient.get("events", EventEntity.class);
myevents.setCache(new InMemoryLRUCache(), CachePolicy.NETWORKFIRST); //Add caching
myevents.get(new KinveyListCallback<EventEntity>()     {
  @Override
  public void onSuccess(EventEntity[] result) { 
    Log.v(TAG, "received "+ results.size() + " events");
  }

  @Override
  public void onFailure(Throwable error)  { 
    Log.e(TAG, "failed to fetch all", error);
  }
});

The expected behavior of the above code will be a call to Kinvey data service to retrieve any data. If the network is unavailable a call to the cache will be made and returned instead.

Offline AppData

Kinvey's Android library provides offline functionality, allowing you to ensure your app is responsive and data is up to date even without a reliable network connection.

You can set an Offline Policy on AppData to allow your app to maintain a local copy of your entities, which will then be persisted with your backend once a connection is restored. The API will locally persist entities as well as maintain a queue of requests performed while offline.

It is implemented by spawning an Android service to execute the queued requests against your Kinvey backend once a connection is available. Offline uses sqlite 3 for maintaining data locally.

Updating the local store

The local store is updated both when on offline save request is executed, and after a get request is executed successfully over the network. An offline get request can return the data saved during an offline save. Offline queries will return previously saved data as well. Queries are not executed on the client, however they will return any entity modifications made while offline.

For example:

  1. While connected to a network, query q returns entities 1, 2, and 3. Offline AppData automatically stores the query and the results.
  2. When a connection is lost, entity 3 is updated with a save request.
  3. While still offline, query q will now return entities 1, 2, and the updated entity 3
  4. If entity 4 is added that meets the criteria for the query, it will not be returned with query q until a connection has been restored.

Usage

To enable offline functionality, you must add the background Service to your application's manifest.xml file and set an OfflinePolicy on the AppData API.

Add Service to Manifest

After entities have been stored locally, the library will kick off a Service to load Entities and execute any queued requests. This is accomplished using Intents, and communication is managed by the operation system. To ensure your application can receive these messages, add the following line to your manifest inside the </application> tag.

<Application>

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


    …  //Activity and other declarations

    <service
            android:name="com.kinvey.android.offline.KinveySyncService"
            android:exported="true" android:process=":backgroundsync" >
        <intent-filter>
            <action android:name="com.kinvey.android.ACTION_OFFLINE_SYNC" />
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            <action android:name="android.net.wifi.STATE_CHANGE" />
        </intent-filter>
    </service>
</Application>

Set OfflinePolicy

You can set an OfflinePolicy on the AppData API to determine the behavior of requests. After getting a reference to AsyncAppData, use the method setOffline(OfflinePolicy policy, OfflineStore store) to configure offline behavior:

AsyncAppData<MyEntity> ad = mKinveyClient.appData("myCollection", MyEntity.class);
ad.setOffline(OfflinePolicy.LOCAL_FIRST, new SqlLiteOfflineStore<MyEntity>(getContext()));

After setting a policy, all methods will use that policy to determine how they should be executed. For example, to get an entity with the _id of "myEntityID", you could use the following code:

AsyncAppData<MyEntity> ad = mKinveyClient.appData("myCollection", MyEntity.class);
ad.setOffline(OfflinePolicy.LOCAL_FIRST, new SqlLiteOfflineStore<MyEntity>(getContext()));
ad.get("myEntityID", new KinveyClientCallback<MyEntity>() {

    @Override
    public void onSuccess(MyEntity arg0) {
        //successfully retrieved entity
    }

    @Override
    public void onFailure(Throwable arg0) {
        //something went wrong!            
    }
});

Offline Policies

  • OfflinePolicy.ONLINE_FIRST - This policy will attempt to execute the request online first, and if that is successful will update the local store with the results. If the request fails due to connectivity issues, then the request will be executed against the local store. If it fails for any other reason such as an Authorization Error, the onFailure callback will be called.

Use this policy if your application's data is constantly changing on the backend, but you want to support offline mode.

  • OfflinePolicy.LOCAL_FIRST - This policy will attempt to execute the request against the local store first. If the request is a Get, and the data cannot be found in the local store, then an online request will be attempted. If that suceeds, the store will be updated, and onSuccess will be called. If that fails, then onFailure will be called. For save requests, the local store will be updated and the entity will be returned through the onSuccess callback.

Use this policy if each user has their own data, and updates are not constantly required from your backend.

  • OfflinePolicy.ALWAYS_ONLINE - This policy will not use any local storage or queueing, and will execute every request online. If no network connection is available, errors will be returned through the onFailure callback.

Use this policy if your application is fully dependant on data in the backend, and data cannot be stored locally.

For high performance, you can combine CachePolicy.CACHEFIRST and OfflinePolicy.LOCAL_FIRST to retrieve data first from memory, then from disk, and finally over the network.

Got a question?