Using SnappyDB for Caching
Tried out SnappyDB today. SnappyDB is a fast key value store for Android, which uses Google’s native LevelDB along with the Snappy compression algorithm, also from Google.
Setup and usage is dead simple. Add these two lines to your build.gradle:
compile 'com.snappydb:snappydb-lib:0.5.0' compile 'com.esotericsoftware.kryo:kryo:2.24.0'
The first dependency is SnappyDB itself, the second one is Kryo, a framework which is used for object serialization underneath. Call .open to open a database (or create it on first access):
private DB cache; ... // Create/open the cache try { cache = DBFactory.open(context, CACHE_DB_NAME); } catch (SnappydbException e) { Log.e(getClass().getSimpleName(), e.getMessage()); }
Inserting an object is as simple as
// Put the region in the cache cache.put(region.getId(), region);
where region is a POJO I want to cache and the first argument is a unique String identifier used as the key. To retrieve an object from the cache, use .getObject:
Region r = cache.getObject(id, Region.class);
You may check for existence with .exists:
if (cache.exists(id)) ...
The cool thing is that you can store and retrieve any POJO as long as Kryo can figure out how to serialize it. You do not need to implement Serializable, nor do you need to modify your model classes in any way.
Well, that’s almost true. You must make sure your model classes obey the following three rules:
The class must have a default (no-arg) constructor.
The class must not have any (non-static) inner classes.
Any classes referenced in fields of your model class must also obey 1. and 2.
The third one took me a while to figure out, as the exception thrown by Snappy (or rather by Kryo) will tell you
com.snappydb.SnappydbException: Maybe you tried to retrieve an array using this method ? please use getObjectArray instead Class cannot be created (missing no-arg constructor): com.[...]
and you need to carefully read which class is causing the problem. At first, you may find yourself staring in confusion at your model class with its beautiful no-arg constructor, when the problem is really a class referenced in a field of your model that doesn’t have one.
The same goes for inner classes: Kryo may complain that
com.snappydb.SnappydbException: Maybe you tried to retrieve an array using this method ? please use getObjectArray instead Class cannot be created (non-static member class): com.[...]
which means you may need to refactor your model class (and/or its child classes), moving any private inner classes to their own file, making them public and giving them a no-arg constructor. I had to do this for an optimized spatial data structure I was attempting to cache and it was kind of tedious. However, Kryo has its reasons for not storing inner classes and for most of your POJOs this will likely never be an issue.
So the first impression is actually pretty awesome: SnappyDB feels - well - snappy. Cache retrieval for region data in the LOCLET app is on the order of a few milliseconds and there’s virtually no coding overhead for storing stuff (apart from the potential need to refactor some of your model classes). Conceptually, it feels like the right choice for saving simple data in a lightweight fashion.
As a final caveat, beware that SnappyDB itself is not thread-safe (LevelDB underneath is, though). So if your app requires concurrent access, be sure to synchronize your writes/reads manually:
synchronized (cache) { cache.put(region.getId(), region); }










