GithubHelp home page GithubHelp logo

vincentbrison / dualcache Goto Github PK

View Code? Open in Web Editor NEW
513.0 35.0 78.0 602 KB

This android library provide a cache with 2 layers, one in RAM in top of one disk.

License: Apache License 2.0

Java 99.50% Shell 0.50%

dualcache's Introduction

Deprecated

This library is now deprecated in favor of Store which fulfill all the goal of this library.

Android dualcache

API Build Status Android Arsenal

This android library provide a cache with 2 layers, one in RAM in top of one on local storage. This library is highly configurable :

Configurations Disk : Specific serializer Disk : disable
Ram : Specific serializer YES YES
Ram : References YES YES
Ram : disable YES NO
  • Specific serializer : the object stored in cache will be serialized through a serializer provided by yourself.
  • References : the objects stored in Ram are cached through there references (no serialization is done).
  • Disable : the corresponding layer (Ram or disk) is disable.

If you work with specific serializer or references you will have to provide (through an interface) the way of compute the size of cached objects, to be able to correctly execute the [LRU policy] (http://en.wikipedia.org/wiki/Cache_algorithms).

If you do not want to write your own serializer and a json serializer is enough for you, you can use dualcache-jsonserializer which will serialize object using Jackson

The following diagrams are showing how the dualcache is working :

  • DualCache with specific serializer in RAM and specific serializer in disk. dualcache-serializer

  • DualCache with references in RAM and specific serializer in disk. dualcache-serializer-ref

To get the best performance from this library, I recommend that you use larger size for the disk layer than for the Ram layer. When you try to get an object from the cache which is already in the Ram layer, the disk wont be use to keep the best performance from the Ram. If you try to get an object from the cache which is on disk and not on Ram, the object will be loaded into RAM, to ensure better further access time.

The Philosophy behind this library

When you want to use a [cache] (http://en.wikipedia.org/wiki/Cache_\(computing\)) on Android today, you have two possibilities. You whether use :

The thing is the first one only works in RAM, and the second one only on disk (internal memory of the phone). So you need to choose whether if you will use the LruCache (RAM) :

  • Very fast access to your cache.
  • High resources constraints, since the RAM allocated to your application is used for caching.
  • Not persistent among different execution of your app.

Or you will use the DiskLruCache (Disk) :

  • Slower access time than the LruCache.
  • Almost no resources constraints, since the size used on the disk (internal memory), will not impact your application.
  • Persistent among different execution of your app.

The purpose of this library is to provide both features of these two caches, by making them working together. You do not need to ask yourself anymore "Should I use this one or this one ? But this one is persistent, but the other one is faster...". With this library you only use one cache, with two layers, one in RAM, and one in Disk and you configure how they have to work to provide exactly what you need in term of caching for you application.

What's new in 3.0.0

  • Only one dependency to DiskLruCache because apk size matters.
  • Non coupled serializer, with cleaner implementation. Previously default json serializer is now a specific serializer which is available at com.vincentbrison.openlibraries.android:dualcache-jsonserializer:3.1.1.
  • Internal optimizations for better performances.
  • All the configuration is now done through Builder.
  • Better access modifiers to fully hide internal classes.

Concurrent access

Starting with version 2.2.1, the cache is supporting concurrent access. You can perform whatever operations from multiple threads and the cache takes care of the synchronization. More than that, this synchronization is optimized to block the threads only if needed, to get the best performances. In fact, put and get are synchronized on each entry, and the cache itself is locked trough a ReadWriteLock for invalidation operations.

Setup

  • Ensure you can pull artifacts from Maven Central :
repositories {
    mavenCentral()
}
  • And add to your module gradle file :
android {
    packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }
}

dependencies {
    compile 'com.vincentbrison.openlibraries.android:dualcache:3.1.1'

    //compile 'com.vincentbrison.openlibraries.android:dualcache-jsonserializer:3.1.1' // If you
    // want a ready to use json serializer
}

All the configuration of the cache is done when you are building the cache through its Builder class.

Basic examples

Build your cache

First of all, you need to build you cache, through the Builder class.

  1. A cache with a serializer for RAM and disk disable :
cache = new Builder<>(CACHE_NAME, TEST_APP_VERSION, AbstractVehicule.class)
    .enableLog()
    .useSerializerInRam(RAM_MAX_SIZE, new SerializerForTesting())
    .noDisk()
    .build();
  1. A cache with references in RAM and a default serializer on disk :
cache = new Builder<>(CACHE_NAME, TEST_APP_VERSION, AbstractVehicule.class)
    .enableLog()
    .useReferenceInRam(RAM_MAX_SIZE, new SizeOfVehiculeForTesting())
    .useSerializerInDisk(DISK_MAX_SIZE, true, new DualCacheTest.SerializerForTesting(), getContext())
    .build();

You can note that when you build the cache, you need to provide an app version number. When the cache is loaded, if data exist with a inferior number, it will be invalidate. It can be extremely useful when you update your app, and change your model, to avoid crashes. This feature is possible because the DiskLruCache of Jake Wharton implemented this feature.

Put

To put an object into your cache, simply call put :

DummyClass object = new DummyClass();
object = cache.put("mykey", object);

Get

To get an object from your cache, simply call get :

DummyClass object = null;
object = cache.get("mykey");

Use cases

  • Using default serialization on RAM and on disk can be very useful for caching network exchange of data.
  • Using references in RAM and serialization on disk can be very useful to cache bitmaps.

Javadoc

The javadoc provided with this library is fully written and released on Maven.

Testing

All the configurations of the cache are (almost) fully tested through automated tests. If you fork this repo, you can launch them with the gradle command connectedAndroidTest. You need to have a device connected since the tests will be run on every device connected to your computer. An emulator or a [GenyMotion] instance is enough. A report will be available at : /{location of your fork}/lib/build/outputs/reports/androidTests/connected/index.html

License

Copyright 2016 Vincent Brison.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

dualcache's People

Contributors

ardhinata avatar auchri avatar bitdeli-chef avatar gustavkarlsson avatar rslobodian avatar vincentbrison avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dualcache's Issues

Is it possible to serialize to byte array instead of String?

Hi, I can use Java's built-in ObjectOutputStream to serialize my data into a byte array instead of using the heavy JSON. But there might be some byte illegal for String, e.g. '\0' in the middle of the string. Do I have to encode my byte array to something like base64 or can I store the byte array into String directly using charset ISO-8859-1 (8-bit)? Furthermore, I hope byte arrays can be supported directly in interface CacheSerializer.

Bitmap Cache

Hi,

I want to cache Bitmap objects.

I have this:
private static final int RAM_MAX_SIZE = 2048;

DualCacheLogUtils.enableLog();
DualCacheContextUtils.setContext(getApplicationContext());
cache = new DualCacheBuilder("bitmapCache", 1, Bitmap.class)
.useDefaultSerializerInRam(RAM_MAX_SIZE)
.noDisk();

And I have DataHolder where I have reference to "cache" instance.

DataHolder.getInstance().setCache(cache);

When I put object to cache:
key = "data1";
cache.put(key, result);

and immediately I try to get this object with:
Bitmap bm = cache.get(key);

bm is equal to null.

Class that implements SizeOf is returning -> object.getHeight() * object.getWidth() * 4

What I'm doing wrong ?

NoSuchMethodException on invalidateRAM

Hi,

When running unit tests with RobolectricGradleTestRunner I get a NoSuchMethodException exception stack trace when invalidating cache:

java.lang.NoSuchMethodException: java.util.LinkedHashMap.eldest()
    at java.lang.Class.getMethod(Class.java:1786)
    at com.vincentbrison.openlibraries.android.dualcache.RamLruCache.trimToSize(RamLruCache.java:210)
    at com.vincentbrison.openlibraries.android.dualcache.ReferenceLruCache.trimToSize(ReferenceLruCache.java:7)
    at com.vincentbrison.openlibraries.android.dualcache.RamLruCache.evictAll(RamLruCache.java:316)
    at com.vincentbrison.openlibraries.android.dualcache.DualCache.invalidateRAM(DualCache.java:415)
    at com.vincentbrison.openlibraries.android.dualcache.DualCache.invalidate(DualCache.java:407)

I guess this is due to difference between Oracle and Dalvik implementation. Maybe an iterator mechanism could be used when calling "eldest()" fails? This could make unit tests outside Android environment work better. What do you think?

Thanks for working on this library! :)

Log to the developer when trying to cache a bigger object than the DISK_MAX_SIZE

Not a bug just a little improvment.

When you try to cache an obect bigger than the DISK_MAX_SIZE you've set, nothing is telling you something is wrong and it simply does nothing.

For my case it was on this part of the put method, the exception was not throw

if (mDiskMode.equals(DualCacheDiskMode.ENABLE_WITH_DEFAULT_SERIALIZER)) {
                try {
                    DiskLruCache.Editor editor = mDiskLruCache.edit(key);
                    editor.set(0, jsonStringObject);
                    editor.commit();
                } catch (IOException e) {
                    DualCacheLogUtils.logError(e);
                }
            }

No suitable constructor found for type

I use the following to to cache Bitmaps:

DualCacheLogUtils.enableLog();
DualCacheContextUtils.setContext(RadioApplication.getAppContext());
cache = new DualCacheBuilder<Bitmap>(CACHE_NAME, CACHE_VERSION, Bitmap.class)
                .useReferenceInRam(CACHE_RAM, new SizeOfBitmap())
                .useDefaultSerializerInDisk(CACHE_DISK, true);

Storing seems to work fine, but when trying to retrieve an entry from cache, I get the following:

I/dualcache: Entry for e5429ada18f6df2de9c9870c379b7eb4 is on disk.
E/dualcache: error : 
    com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class android.graphics.Bitmap]: can not instantiate from JSON object (need to add/enable type information?)
    at [Source: {"mStackTrace":null,"mBuffer":null,"mRestorePolicyInfo":null,"mFinalizer":["android.graphics.Bitmap$BitmapFinalizer",{"mStackTrace":null,"mIsPreloaded":false,"mNativeBitmap":2140966016,"mPixelsIsAllocated":true,"mRecycled":false,"mBitmapSize":878000}],"mNinePatchChunk":null,"mLayoutBounds":null,"mIsMutable":false,"mIsPreloading":false,"mIsPremultiplied":true,"mIsRestorable":false,"mInUse":false,"mNativeBitmap":2140966016,"mNativeBitmapFreed":false,"mHeight":439,"mPixelsIsAllocated":true,"mRecycled":false,"mDensity":480,"mBitmapSize":878000,"mWidth":500}; line: 1, column: 2]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1063)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:264)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3051)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2146)
    at com.vincentbrison.openlibraries.android.dualcache.lib.DualCache.get(DualCache.java:410)

Add feature to remove from cache

Is it really possible there is no way to remove from cache. Something like cache.remove(key)?
Example, I call web service to get some object. I want to cache that object (the way of implementing of cache is not important to me). What is important is that when I use web service to update that object I want to invalidate cache. I think it is very common requirement, but cannot find any good library which does this.

setting expiry time

I think it would be a nice addition if one could give a maximum TTL when storing an object (default 0 = forever). Then when an object is requested from cache it is only returned if it hasn't expired, yet.

Flush ram cache to disk

Is there a possibility to flush the ram cache to disk? We need to persist the cached data

CacheSerializer with direct access to DiskLruCache stream

Currently, CacheSerializer forces everything to be a String. This can be inefficient for data that is not naturally a String since it requires creating a String just to store the data, particularly if no ram serializer is used. However, DiskLruCache exposes streams that can be used directly to write data. It would be helpful to allow a version of CacheSerializers which can use these streams.

Apache is deprecated

import org.apache.commons.io.IOUtils;
Please remove any dependencies to apache.

Param usePrivateFiles in Builder.useSerializerInDisk() is missleading

Javadoc for usePrivateFiles params in Builder.useSerializerInDisk() says: "true if you want to use {@link Context#MODE_PRIVATE} with the default disk cache folder."

But, as far as I see, both folder below refers to the internal storage and Context.MODE_PRIVATE is used by default:

  • context.getDir(CACHE_FILE_PREFIX + this.id, Context.MODE_PRIVATE)
  • new File(context.getCacheDir().getPath() + "/" + CACHE_FILE_PREFIX + "/" + this.id)

So, the only difference is the path: later creates folder in the cache folder, which might be cleaned-up by the system.

NullPointerException

After changing the language on my phone, I got following exception:

java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:304)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
        at java.util.concurrent.FutureTask.run(FutureTask.java:242)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.jakewharton.disklrucache.DiskLruCache$Editor.set(int, java.lang.String)' on a null object reference
        at com.vincentbrison.openlibraries.android.dualcache.lib.DualCache.put(DualCache.java:313)
        at ...
        at android.os.AsyncTask$2.call(AsyncTask.java:292)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)#
        at java.lang.Thread.run(Thread.java:818)

DualCache#313

What about closing?

DiskLruCache implements Closeable which leads me to believe it should be properly closed when it's done.

I see no way of doing that in the DualCache interface. Shouldn't DualCache also implement Closeable to allow for closing the underlying DiskLruCache?

How to deal with collection with generic

Hi,
How to deal this case,I want to put some data like ArrayList<HomeBannerModel> to DualCache, and get ArrayList<HomeBannerModel> ,but The third parameter type of Build is Class,not a Type

    /**
     * Start the building of the cache.
     * @param id is the id of the cache (should be unique).
     * @param appVersion is the app version of the app. If data are already stored in disk cache
     * with previous app version, it will be invalidate.
     * @param clazz is the class of object to store in cache.
     */
    public Builder(String id, int appVersion, Class<T> clazz) {
        this.id = id;
        this.appVersion = appVersion;
        this.clazz = clazz;
        this.ramMode = null;
        this.diskMode = null;
        this.logEnabled = false;
    }

license & Proguard options

Hey ,

Thanks for the very helpful lib ,

how can i include your license in my app for release

and what is the configurations for proguard

thanks in advance

Provide examples for caching Bitmaps, Files etc

I want to use your library for disk caching some JPG images. I don't see how to do this, I looked at your methods

useCustomSerializerInDisk()

and

useDefaultSerializerInDisk()

both seem to assume I want to store data as Strings, which isn't a very good assumption.

Any putSync method/callback?

            dualCache.put(key, object);
            logger.debug("put_result: " + "key " + key + "/" + object);
            logger.debug("demo_get: " + "key " + key + "/" + dualCache.get(key));

Sometimes dualCache.get(key) returns null. Is there any callback or sync way to put object in cache?

java.lang.VerifyError: com/vincentbrison/openlibraries/android/dualcache/lib/DualCache

Why do I initialize DualCache complains

This is my initialization code

public void onCreate() {
super.onCreate();
DualCacheLogUtils.enableLog();
DualCacheContextUtils.setContext(getApplicationContext());
DualCache mCache = new DualCacheBuilder(mCacheId, 2, String.class)
.useDefaultSerializerInRam(mRamCacheSize)
.useDefaultSerializerInDisk(mDiskCacheSize, true);
}

This is the error information

java.lang.VerifyError: com/vincentbrison/openlibraries/android/dualcache/lib/DualCache
at com.vincentbrison.openlibraries.android.dualcache.lib.DualCacheBuilder.(DualCacheBuilder.java:18)
at com.jbp.minegold.MinegoldApplication.onCreate(MinegoldApplication.java:31)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1000)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4502)
at android.app.ActivityThread.access$1300(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1336)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:5153)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564)
at dalvik.system.NativeStart.main(Native Method)

examples or more info

hello,
now i want to use doublecache.
i prepared all the needed gradle lines and now i want to instantiate the caching service object.

In your description this is the lines to do that:

cache = new Builder<>(CACHE_NAME, TEST_APP_VERSION, AbstractVehicule.class)
    .enableLog()
    .useReferenceInRam(RAM_MAX_SIZE, new SizeOfVehiculeForTesting()
new SizeOfVehiculeForTesting())
    .useSerializerInDisk(DISK_MAX_SIZE, true, new DualCacheTest.SerializerForTesting(), getContext())
    .build();

but what is the type of cache object ?
what is AbstractVehicule.class means, i try to get it's declaration to understand but i didn't found comments?
what should be the default or recommanded number for RAM_MAX_SIZE, DISK_MAX_SIZE
what is new DualCacheTest.SerializerForTesting(), new SizeOfVehiculeForTesting()

I really don't understand how to use it and i didn't find any tutorials, examples, real codes help?
so please help?

Got error when i am trying to create jar file

hi vincentbrison ,i am tring to generate library using gradle.i installed gradle independently i dont have android studio setup.but when i ma trying to create jar using gradlew.bat got errr Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_
how can i solve it?

IllegalStateException on reading from Cache

I have a sample Activity which tries to add Bitmaps to the cache:

   
    DualCache<Bitmap> mCache;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate ( savedInstanceState );
        setContentView ( R.layout.activity_main );

        CacheSerializer<Bitmap> jsonSerializer = new JsonSerializer<> ( Bitmap.class );
        mCache = new Builder<Bitmap> ( CACHE_NAME, TEST_APP_VERSION )
                .enableLog ( )
                .useSerializerInRam ( RAM_MAX_SIZE, jsonSerializer )
                .useSerializerInDisk ( DISK_MAX_SIZE, true, jsonSerializer, getApplicationContext ( ) )
                .build ( );

        Button put  = (Button) findViewById ( R.id.put );
        put.setOnClickListener ( new View.OnClickListener ( ) {
            @Override
            public void onClick(View view) {
                Bitmap bm = BitmapFactory.decodeResource ( getResources ( ), R.mipmap.ic_launcher );
                mCache.put ( "a", bm );
            }
        } );


        Button get = (Button) findViewById ( R.id.get );
        get.setOnClickListener ( new View.OnClickListener ( ) {
            @Override
            public void onClick(View view) {
                Bitmap bitmap = mCache.get ( "a" );
                ImageView imv = (ImageView) findViewById ( R.id.imageView );
                if (bitmap != null) {
                    imv.setImageBitmap ( bitmap );
                }
            }
        } );
    }

I first press put button (there is no error) and then get. But after pressing get I get this error:

E/AndroidRuntime: FATAL EXCEPTION: main
                  java.lang.IllegalStateException
                      at com.vincentbrison.openlibraries.android.dualcache.JsonSerializer.fromString(JsonSerializer.java:38)
                      at com.vincentbrison.openlibraries.android.dualcache.DualCache.get(DualCache.java:246)

Crashes on Prograud with minifyEnabled true

It's working perfectly fine in debug mode. But once I try with signed apk having progaurd with minifyEnabled true, it crashes.
I have tried using
-keep class com.vincentbrison.* { ; }
-dontwarn com.vincentbrison.

But no luck yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.