Android library to easily serialize and cache your objects to disk using key/value pairs.

Overview

Deprecated

This project is no longer maintained. No new issues or pull requests will be accepted. You can still use the source or fork the project to suit your needs.

Reservoir

Reservoir is a simple library for Android that allows you to easily serialize and cache your objects to disk using key/value pairs.

Download

Including in your project

Add the jcenter repository to your gradle build file if it's not already present:

repositories {
    jcenter()
}

Next, add Reservoir as a dependency:

dependencies {
    compile 'com.anupcowkur:reservoir:3.1.0'
}

Usage

Initialize

Reservoir uses the internal cache storage allocated to your app. Before you can do anything, you need to initialize Reservoir with the cache size.

try {
    Reservoir.init(this, 2048); //in bytes
} catch (IOException e) {
        //failure
}

If you want to pass in a custom GSON instance for whatever reason, you can do that too:

try {
    Reservoir.init(this, 2048, myGsonInstance);
} catch (IOException e) {
        //failure
}

The best place to do this initialization would be in your application's onCreate() method.

Since this library depends directly on DiskLruCache, you can refer that project for more info on the maximum size you can allocate etc.

Put stuff

You can put objects into Reservoir synchronously or asynchronously.

Async put will you give you a callback on completion:

//Put a simple object
Reservoir.putAsync("myKey", myObject, new ReservoirPutCallback() {
            @Override
            public void onSuccess() {
                //success
            }

            @Override
            public void onFailure(Exception e) {
                //error
            }
        });


//Put collection
List<String> strings = new ArrayList<String>();
strings.add("one");
strings.add("two");
strings.add("three");
Reservoir.putAsync("myKey", strings, new ReservoirPutCallback() {
            @Override
            public void onSuccess() {
                //success
            }

            @Override
            public void onFailure(Exception e) {
                //error
            }
        });        

synchronous put:

//Put a simple object
try {
    Reservoir.put("myKey", myObject);
} catch (IOException e) {
    //failure;
}

//Put collection
List<String> strings = new ArrayList<String>();
strings.add("one");
strings.add("two");
strings.add("three");
try {
    Reservoir.put("myKey", strings);
} catch (IOException e) {
    //failure;
}

Async put uses the standard AsyncTask provided by the Android framework.

Get Stuff

You can get stuff out of Reservoir synchronously or asynchronously as well.

Async get will give you a callback on completion:

//Get a simple object
Reservoir.getAsync("myKey", MyClass.class, new ReservoirGetCallback<MyClass>() {
            @Override
            public void onSuccess(MyClass myObject) {
                //success
            }

            @Override
            public void onFailure(Exception e) {
                //error
            }
        });

//Get collection
Type resultType = new TypeToken<List<String>>() {}.getType();
Reservoir.getAsync("myKey", resultType, new ReservoirGetCallback<List<String>>() {
            @Override
            public void onSuccess(List<String> strings) {
                //success
            }

            @Override
            public void onFailure(Exception e) {
                //error
            }
        });        

synchronous get:

//Get a simple object
try {
    Reservoir.get("myKey", MyClass.class);
} catch (IOException e) {
        //failure
}

//Get collection
Type resultType = new TypeToken<List<String>>() {}.getType();
try {
    Reservoir.get("myKey", resultType);
} catch (IOException e) {
        //failure
}

Check for existence

If you wish to know whether an object exists for the given key, you can use:

try {
    boolean objectExists = Reservoir.contains("myKey");
} catch (IOException e) {}

Delete Stuff

deleting stuff can also be synchronous or asynchronous.

Async delete will give you a callback on completion:

Reservoir.deleteAsync("myKey", new ReservoirDeleteCallback() {
            @Override
            public void onSuccess(MyClass myObject) {
                //success
            }

            @Override
            public void onFailure(Exception e) {
                //error
            }
        });

synchronous delete:

try {
    Reservoir.delete("myKey");
} catch (IOException e) {
        //failure
}

Clearing the cache

You can clear the entire cache at once if you want.

asynchronous clear:

Reservoir.clearAsync(new ReservoirClearCallback() {
            @Override
            public void onSuccess() {
                try {
                    assertEquals(0, Reservoir.bytesUsed());
                } catch (Exception e) {
                   
                }
            }

            @Override
            public void onFailure(Exception e) {
                
            }
        });

synchronous clear:

try {
    Reservoir.clear();
} catch (IOException e) {
        //failure
}

RxJava

Reservoir is down with RxJava! All the async methods have RxJava variants that return observables. These observables are scheduled on a background thread and observed on the main thread by default (you can change this easily by assigning your own schedulers and observers to the returned observable).

First, you'll need to add RxJava dependency to your app since Reservoir does not come bundled with it:

compile 'io.reactivex:rxandroid:<rxandroid-version>' - tested with v1.2.1
compile 'io.reactivex:rxjava:<rxjava-version>' - tested with v1.1.6

Then you can use the RxJava variants of all the regular Reservoir methods.

put:

//Put a simple object
Reservoir.putUsingObservable("myKey", myObject) returns Observable<Boolean>

//Put collection
List<String> strings = new ArrayList<String>();
strings.add("one");
strings.add("two");
strings.add("three");
Reservoir.putUsingObservable("myKey", strings) returns Observable<Boolean>

get:

//Get a simple object
Reservoir.getUsingObservable("myKey", MyClass.class) returns Observable<MyClass>

//Get collection
//Note : Rx observables return items one at a time. So even if you put in a complete collection, the items in the collection will be returned 
//one by one by the observable.
Type collectionType = new TypeToken<List<String>>() {}.getType();
Reservoir.getUsingObservable("myKey", String.class, collectionType) returns Observable<String>

delete:

Reservoir.deleteUsingObservable("myKey") returns Observable<Boolean>

clear:

Reservoir.clearUsingObservable() returns Observable<Boolean>

If you'd like to see examples of using these observables, check out the tests in the sample application.

FAQs

What kind of objects can I add to Reservoir?

Anything that GSON can serialize.

What happens if my cache size is exceeded?

Older objects will be removed in a LRU (Least Recently Used) order.

Can I use this a SharedPreferences replacement?

NO! This is a cache. You should store stuff in here that is good to have around, but you wouldn't mind if they were to be removed. SharedPreferences are meant to store user preferences which is not something you want to lose.

Sample

Check out the sample application tests for complete examples of API usage.

Contributing

Contributions welcome via Github pull requests.

Credits

Reservoir is just a tiny little convenience wrapper around the following fantastic projects:

License

This project is licensed under the MIT License. Please refer the License.txt file.

Comments
  • cannot access Observable class file for rx.Observable not found

    cannot access Observable class file for rx.Observable not found

    this does not happen to putAsync. This only happens to getAsync. My code:

    final Type resultType = new TypeToken<List<Category>>() {
            }.getType();
            Reservoir.getAsync("categories", resultType, new ReservoirGetCallback<List<Category>>() {
                @Override
                public void onSuccess(List<Category> categories) {
                    //success
                    Log.i(TAG, "onSuccess");
                }
    
                @Override
                public void onFailure(Exception e) {
                    //error
                    Log.e(TAG, "onFailure", e);
                    fetchCatsFromRemote(object);
                }
            });
    
    opened by ericntd 10
  • putReservoir success, getReservoir failure

    putReservoir success, getReservoir failure

    I have a strange behavior. I have called WS with okhttp + retrofit and I have retrieved POJO. Then I want save these objects with Reservoir. My method putReservoir goes in onSuccess but getReservoir goes in onFailure. In both side, I'm using the same object.

    As a consequence, I have another question ==> Where are data on the phone ?

    opened by aat-antoine 10
  • The NPE in the SimpleDiskCache.writeMetadata(...)

    The NPE in the SimpleDiskCache.writeMetadata(...)

    I don't know if I did something wrong with the library, but I've got a new crash report from a user. Could you check it?

    The stack trace:

    java.lang.NullPointerException
           at com.anupcowkur.reservoir.SimpleDiskCache.writeMetadata(SimpleDiskCache.java:108)
           at com.anupcowkur.reservoir.SimpleDiskCache.openStream(SimpleDiskCache.java:73)
           at com.anupcowkur.reservoir.SimpleDiskCache.put(SimpleDiskCache.java:95)
           at com.anupcowkur.reservoir.SimpleDiskCache.put(SimpleDiskCache.java:83)
           at com.anupcowkur.reservoir.Reservoir.put(Reservoir.java:47)
          ...
    
    opened by makovkastar 6
  • NullPointerException in Reservoir.java:180

    NullPointerException in Reservoir.java:180

    One of my customers is frequently seeing the following issue in a beta version of their app. We've seen over 60+ non-fatals over 3 separate instances affecting 10+ users in a beta test group of around 15

    Trace:

    java.lang.NullPointerException
           at com.anupcowkur.reservoir.Reservoir$GetTask.doInBackground(Reservoir.java:180)
           at com.anupcowkur.reservoir.Reservoir$GetTask.doInBackground(Reservoir.java:163)
           at android.os.AsyncTask$2.call(AsyncTask.java:287)
           at java.util.concurrent.FutureTask.run(FutureTask.java:234)
           at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
           at java.lang.Thread.run(Thread.java:856)
    

    This happens at multiple locations in the app and has no specific trigger. Reservoir has been initiated in the application object like so:

    Reservoir.init(this, 100000);
    

    Seems the cache object might be null in Reservoir.java:180, let me know if you need any more information to reproduce the issue

    opened by sohamtriveous 5
  • separated the callback to onSuccess and onFailure to avoid having to che...

    separated the callback to onSuccess and onFailure to avoid having to che...

    ...ck if e is null each time. Made it abstract class instead of interface so that you only have to implement what you want. You can make it an interface if you want.

    opened by trevor-e 5
  • Can we put multiple keys into cache?

    Can we put multiple keys into cache?

    I want to cache the data with multiple keys and retrieve them. Like for example, first I want to save some data with key A and after that some data with key B and so on. And then retrieve that data based on the keys. Is that possible??

    opened by androidCastle 3
  • null object reference!

    null object reference!

    Thanks for the great library, and here what I am getting

    Attempt to invoke virtual method 'java.lang.String com.anupcowkur.reservoir.SimpleDiskCache$StringEntry.getString()' on a null object reference

    Any help please?

    opened by khaledkhj 3
  • Declares multiple JSON fields named id

    Declares multiple JSON fields named id

    The problem is kinda weird. When I try to store objects that have ID variables inside, I face this exception:

    java.lang.IllegalArgumentException: class xxxxx.Article declares multiple JSON fields named id .....

    How to solve this problem?

    opened by erfannf 3
  • Delete operation seems not to work

    Delete operation seems not to work

    Reservoir.put("lol", "fsdfasdfa"); Reservoir.delete("lol"); Reservoir.contains("lol") returns true

    Reservoir.put("lol", "fsdfasdfa"); Reservoir.clear() Reservoir.contains("lol") returns false

    opened by AndroidGecko 3
  • Multiple reservoirs with separate initialization

    Multiple reservoirs with separate initialization

    I think this library should not be initialized via static method, because it prevents creating multiple reservoirs and using it in different libraries.

    opened by virl 3
  • Can' t set allowBackup to false

    Can' t set allowBackup to false

    Due to this issue https://code.google.com/p/android/issues/detail?id=70073 and the fact the the reservoir library explicitly sets allowBackup to true, I can't set allowBackup to false.

    Can allowBackup=true be removed from the manifest?

    opened by ciskeboekelo 3
Releases(3.1.0)
  • 3.1.0(Aug 3, 2016)

    • Fixes a bug (#37) where RxJava was not an optional dependency
    • Changes public API to use actionUsingObservable format for Rx variants of methods to avoid confusion with regular Async methods that use AsyncTasks. For example, Rx variant of getAsyncis now getUsingObservable.
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(Jun 25, 2016)

    • RxJava is now a provided dependency. This means that Reservoir will not include come bundled with it by default saving you a lot of unnecessary methods if you don't want to use RxJava.
    • Apache Commons IO dependency is now removed reducing the method count significantly.
    Source code(tar.gz)
    Source code(zip)
  • 2.1(Aug 15, 2015)

    • Adds support for collections. Now you can pass in your custom type to easily store and retrieve collections.
    • Adds support for custom GSON instance. You can now initialize Reservoir with your own GSON instance with custom configurations.
    Source code(tar.gz)
    Source code(zip)
  • 2.0(Jun 2, 2015)

    • RxJava support.
    • Added clear and clearAsync methods to the public API. These methods completely clear the cache and delete all the stored key-value pairs.
    • Added tests.
    • Moved distribution from Maven Central to JitPack.
    • Reservoir now uses a separate cache directory inside the application specific cache directory to store data.
    • Fix: If init is not called before calling any other methods, an IllegalStateException is thrown.
    • Fix: reservoir now checks if size of object being inserted is greater than cache size and throws and IOException if it is.
    • Fix: removed allowBackup from manifest.
    Source code(tar.gz)
    Source code(zip)
  • 1.2(Jun 1, 2015)

    • Added delete and deleteAsync.
    • Removed launcher icons and renamed resources to prevent conflicts with app that uses lib.
    • Fix: typos in java docs.
    • Fix: get and getAsync would not throw NullPointerException if the returned object was null.
    Source code(tar.gz)
    Source code(zip)
  • 1.1.1(Jun 1, 2015)

  • 1.1(Jun 1, 2015)

  • 1.0(Jun 1, 2015)

Owner
Anup Cowkur
Anup Cowkur
DiskCache - Simple and readable disk cache for kotlin and android applications

DiskCache Simple and readable disk cache for kotlin and android applications (with journaled lru strategy) This is a simple lru disk cache, based on t

Giovanni Corte 14 Dec 2, 2022
Java implementation of a Disk-based LRU cache which specifically targets Android compatibility.

Disk LRU Cache A cache that uses a bounded amount of space on a filesystem. Each cache entry has a string key and a fixed number of values. Each key m

Jake Wharton 5.7k Dec 31, 2022
Reactor is key value database and is a great alternative to Shared Preferences.

Reactor Reactor is a fast and secure key-value library for Android, and has an embedded database based on the JSON structure and is a great alternativ

mr amir abbas 37 Oct 30, 2022
✔️ Secure, simple key-value storage for Android

Hawk 2.0 Secure, simple key-value storage for android Important Note This version has no backward compatibility with Hawk 1+ versions. If you still wa

Orhan Obut 3.9k Dec 20, 2022
Keep data as a linked list on disk. A alternative way to reduce redundant operation for DiskLruCache

DiskLinkedList Keep data as a linked list on disk. An alternative way to reduce redundant operation for DiskLruCache Use-case Android have build-in Di

Cuong V. Nguyen 6 Oct 29, 2021
A simple Android utils library to write any type of data into cache files and read them later.

CacheUtilsLibrary This is a simple Android utils library to write any type of data into cache files and then read them later, using Gson to serialize

Wesley Lin 134 Nov 25, 2022
a simple cache for android and java

ASimpleCache ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架。轻量到只有一个java文件(由十几个类精简而来)。 1、它可以缓存什么东西? 普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 b

Michael Yang 3.7k Dec 14, 2022
An easy-to-use, cross-platform measurement tool that pulls data out of CD pipelines and analysis the four key metrics for you.

Maintained by SEA team, ThoughtWorks Inc. Read this in other languages: English, 简体中文 Table of Contents About the Project Usage How to Compute Contrib

Thoughtworks 277 Jan 7, 2023
A library to quickly and easily enable multiple monitoring & support platforms for your mobile apps

You have a small team. Setting up crash reporting tools, event tracking tools, and log management services is not what you want to spend your hours do

Percolate 65 Aug 8, 2022
Small Android library to help you incorporate MVP, Passive View and Presentation Model patterns in your app

DroidMVP About DroidMVP is a small Android library to help you incorporate the MVP pattern along with Passive View and Presentation Model (yes, those

Andrzej Chmielewski 225 Nov 29, 2022
SharedPreference Library to save all types including your custom types and observe them if need be.

A SharedPreference Library that can be used to store all types including your custom classes and observe them too if needed.

Ehma Ugbogo 18 Nov 10, 2021
Trail is a simple logging system for Java and Android. Create logs using the same API and the library will detect automatically in which platform the code is running.

Trail Trail is a simple logging system for Java and Android. Create logs using the same API and the library will detect automatically in which platfor

Mauricio Togneri 13 Aug 29, 2022
compaKTset is a small library aimed at providing you with the most memory efficient Set implementation for any particular data type of your choosing.

compaKTset is a small library aimed at providing you with the most memory efficient Set implementation for any particular data type of your choosing.

Ignat Beresnev 3 Nov 16, 2021
A lightweight library for config and using SharedPreferences

preferences-helper SharePreferences is very popular with any project and all most all project has SharePreferences for saving data. This library will

Khang Tran 23 May 8, 2021
A beautiful set of predefined colors and a set of color methods to make your Android development life easier.

Colours is a port of the Colours Library for iOS made by my good friend Ben Gordon. You can find that project here. Installation Maven Central Colours

Matthew York 634 Dec 28, 2022
[] Define and render UI specs on top of your Android UI

dspec A simple way to define and render UI specs on top of your Android UI. Usage Enclose the target UI with a DesignSpecFrameLayout, usually the root

Lucas Rocha 561 Dec 16, 2022
Utility for detecting and notifying when your Android app goes background / becomes foreground

Foredroid Utility for detecting and notifying when your Android app goes background / becomes foreground. API-level 14+. Usage: Initialise Foreground

Steve Liles 151 Nov 29, 2022
A simple library for validating user input in forms using annotations.

ValidationKomensky for Android A simple library for validating user input in forms using annotations. Features: Validate all views at once and show fe

Inmite s.r.o. 512 Nov 20, 2022
High level parsing to ensure your input is in the right shape and satisfies all constraints that business logic requires.

Parsix High level parsing to ensure your input is in the right shape and satisfies all constraints that business logic requires. It is highly inspired

null 190 Oct 16, 2022