All Projects → appmattus → Layercache

appmattus / Layercache

Licence: apache-2.0
Caching made simple for Android and Java.

Programming Languages

kotlin
9241 projects

Projects that are alternatives of or similar to Layercache

Kinto.js
An Offline-First JavaScript Client for Kinto.
Stars: ✭ 268 (+72.9%)
Mutual labels:  hacktoberfest, cache
Bigcache
Efficient cache for gigabytes of data written in Go.
Stars: ✭ 5,304 (+3321.94%)
Mutual labels:  hacktoberfest, cache
Drone Cache
A Drone plugin for caching current workspace files between builds to reduce your build times
Stars: ✭ 194 (+25.16%)
Mutual labels:  hacktoberfest, cache
React Esi
React ESI: Blazing-fast Server-Side Rendering for React and Next.js
Stars: ✭ 537 (+246.45%)
Mutual labels:  hacktoberfest, cache
Typerep Map
⚡️Efficient implementation of Map with types as keys
Stars: ✭ 85 (-45.16%)
Mutual labels:  hacktoberfest, cache
Pokeapi Js Wrapper
PokeAPI browser wrapper, fully async with built-in cache
Stars: ✭ 129 (-16.77%)
Mutual labels:  hacktoberfest, cache
Memento
Memento is a development-only tool that caches HTTP calls once they have been executed.
Stars: ✭ 380 (+145.16%)
Mutual labels:  hacktoberfest, cache
Offix
GraphQL Offline Client and Server
Stars: ✭ 694 (+347.74%)
Mutual labels:  hacktoberfest, cache
Hazelcast Hibernate
A distributed second-level cache for Hibernate
Stars: ✭ 24 (-84.52%)
Mutual labels:  hacktoberfest, cache
Lru Cache Node
A lighting fast cache manager for node with least-recently-used policy.
Stars: ✭ 120 (-22.58%)
Mutual labels:  hacktoberfest, cache
Strapi Middleware Cache
🔌 A cache middleware for https://strapi.io
Stars: ✭ 146 (-5.81%)
Mutual labels:  hacktoberfest, cache
Pagermon
Multimon-ng pager message parser and viewer
Stars: ✭ 154 (-0.65%)
Mutual labels:  hacktoberfest
Rot.js
ROguelike Toolkit in JavaScript. Cool dungeon-related stuff, interactive manual, documentation, tests!
Stars: ✭ 2,002 (+1191.61%)
Mutual labels:  hacktoberfest
Electricitymap Contrib
A real-time visualisation of the CO2 emissions of electricity consumption
Stars: ✭ 2,138 (+1279.35%)
Mutual labels:  hacktoberfest
Android
DuckDuckGo Android App
Stars: ✭ 2,290 (+1377.42%)
Mutual labels:  hacktoberfest
Demeter
Demeter is a tool for scraping the calibre web ui
Stars: ✭ 155 (+0%)
Mutual labels:  hacktoberfest
Gatsby Plugin Algolia
A plugin to push to Algolia based on graphQl queries
Stars: ✭ 154 (-0.65%)
Mutual labels:  hacktoberfest
Meteor Partitioner
Transparently divide a single meteor app into several different instances shared between different groups of users.
Stars: ✭ 153 (-1.29%)
Mutual labels:  hacktoberfest
Pully
A simple CLI and library for downloading high quality YouTube videos!
Stars: ✭ 153 (-1.29%)
Mutual labels:  hacktoberfest
Go Dash
A Go library for generating MPEG-DASH manifests.
Stars: ✭ 153 (-1.29%)
Mutual labels:  hacktoberfest

layercache

CI codecov

Caching made simple for Android and Kotlin.

An important component of building offline-first architectures is to implement caching.

An offline-first architecture initially tries to fetch data from local storage and, failing that, requests the data from the network. After being retrieved from the network, the data is cached locally for future retrieval. This helps to ensure that network requests for the same piece of data only occur once—with subsequent requests satisfied locally.

At its simplest, a cache is nothing more than a key-value store with a getter and setter.

interface Cache<Key : Any, Value : Any> {
    suspend fun get(key: Key): Value?
    suspend fun set(key: Key, value: Value)
}

The real power comes when we are able to compose two caches into a new cache. A memory cache should have a single responsibility to store data in memory, and a disk cache a single responsibility to store data on disk.

val cache = memoryCache.compose(diskCache)

For more details read Caching made simple on Android or watch the talk from droidcon London 2017.

Getting started

Base module

implementation("com.appmattus.layercache:layercache:<latest-version>")

Composing two caches

When get is called on the composed cache, the first cache will be checked and if available returned. If not the second cache will be checked and if available set in the first cache and returned.

composedCache: Cache<Key, Value> = firstCache.compose(secondCache)

Transforming values

Transform values between data types. This can be used for serialisation and encryption amongst other things. i.e. Cache<Key, Value> → Cache<Key, MappedValue>

For two way transformations:

val cache: Cache<Key, Value> = ...
val valueTransform: Cache<Key, MappedValue> = cache.valueTransform(transform, inverseTransform)

// or

val cache: Cache<Key, Value> = ...
val valueTransform: Cache<Key, MappedValue> = cache.valueTransform(TwoWayTransform)

One way transforms return a Fetcher instead of Cache, but otherwise work in the same way. A Fetcher simply implements no-op for set and evict.

val fetcher: Fetcher<Key, Value> = ...
val valueTransform: Cache<Key, MappedValue> = cache.valueTransform(transform)

// or

val fetcher: Fetcher<Key, Value> = ...
val valueTransform: Cache<Key, MappedValue> = cache.valueTransform(OneWayTransform)
Encrypting values
implementation("com.appmattus.layercache:layercache-android-encryption:<latest-version>")

There is support for encrypting string keys and string values (in any cache) on Android with the layercache-android-encryption module. The library is using Google Tink to perform the encryption using AES-256 SIV for keys and AES-256 GCM for values.

// Encrypt key and value when both are strings
val cache: Cache<String, String> = ...
val encryptedCache = cache.encrypt(context)

// Both key and value stored encrypted in `cache`
encryptedCache.set("hello", "world")

// Encrypt values only when just the value is a string
val cache: Cache<Key, String> = ...
val encryptedCache = cache.encryptValues(context)

// Just value stored encrypted in `cache`
encryptedCache.set("hello", "world")

Transforming keys

Transform keys to a different data type. i.e. Cache<Key, Value> → Cache<MappedKey, Value>

val cache: Cache<Key, Value> = ...
val keyTransform: Cache<MappedKey, Value> = cache.keyTransform(transform)

// or

val cache: Cache<Key, Value> = ...
val keyTransform: Cache<MappedKey, Value> = cache.keyTransform(OneWayTransform)

Re-using in flight requests

If a get request is already in flight then this ensures the original request is returned. This may be necessary for disk and network requests along with transformations that take time to execute.

val newCache: Cache<Key, Value> = cache.reuseInflight()

Serializer module

implementation("com.appmattus.layercache:layercache-serializer:<latest-version>")

Configures a transformation from JSON to a serialisable data class and vice-versa. This is useful to store data on disk or in a database. i.e. Cache<Key, String> → Cache<Key, Value>

@Serialize
data class Value(val value)

val cache: Cache<Key, String> = ...

val objectCache: Cache<Key, Value> = cache.jsonSerializer(Value::class.serializer())

Android base module

implementation("com.appmattus.layercache:layercache-android:<latest-version>")

LruCache

val memoryCache: Cache<Key, Value> = Cache.createLruCache(maxSize: Int)

// or

val memoryCache: Cache<Key, Value> = Cache.fromLruCache(...)

DiskLruCache

val diskCache: Cache<String, String> = Cache.createDiskLruCache(directory: File, maxSize: Long)

// or

val diskCache: Cache<String, String> = Cache.fromDiskLruCache(...)

SharedPreferences

Create a cache backed by shared preferences.

val sharedPreferences = context.getSharedPreferences("filename", Context.MODE_PRIVATE)

val anyValueCache: Cache<String, Any> =
        sharedPreferences.asCache()

val stringValueCache: Cache<String, String> =
        sharedPreferences.asStringCache()

val stringSetValueCache: Cache<String, Set<String>> =
        sharedPreferences.asStringSetCache()

val intValueCache: Cache<String, Int> =
        sharedPreferences.asIntCache()

val floatValueCache: Cache<String, Float> =
        sharedPreferences.asFloatCache()

val booleanValueCache: Cache<String, Boolean> =
        sharedPreferences.asBooleanCache()

val longValueCache: Cache<String, Long> =
        sharedPreferences.asLongCache()
EncryptedSharedPreferences
implementation("androidx.security:security-crypto:<latest-version>")

Use Jetpack Security to provide a cache backed by encrypted shared preferences where keys and values are both encrypted.

val masterKey = MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()

val sharedPreferences = EncryptedSharedPreferences.create(
    context,
    "filename",
    masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

val anyValueCache: Cache<String, Any> =
        sharedPreferences.asCache()

val stringValueCache: Cache<String, String> =
        sharedPreferences.asStringCache()

val stringSetValueCache: Cache<String, Set<String>> =
        sharedPreferences.asStringSetCache()

val intValueCache: Cache<String, Int> =
        sharedPreferences.asIntCache()

val floatValueCache: Cache<String, Float> =
        sharedPreferences.asFloatCache()

val booleanValueCache: Cache<String, Boolean> =
        sharedPreferences.asBooleanCache()

val longValueCache: Cache<String, Long> =
        sharedPreferences.asLongCache()

Android LiveData module

implementation("com.appmattus.layercache:layercache-android-livedata:<latest-version>")

Given a cache we can convert it for use with LiveData. This makes the getter return a LiveDataResult which can be one of Loading, Success or Failure.

val liveDataCache = cache.toLiveData()

liveDataCache.get("key").observe(owner) { liveDataResult ->
    when (liveDataResult) {
        is LiveDataResult.Loading -> {
            // display in progress
        }
        is LiveDataResult.Success -> {
            // display liveDataResult.value
        }
        is LiveDataResult.Failure -> {
            // display liveDataResult.exception
        }
    }
}

Download Maven Central

dependencies {
    implementation("com.appmattus.layercache:layercache:<latest-version>")

    // To use with the Kotlin serializer
    implementation("com.appmattus.layercache:layercache-serializer:<latest-version>")

    // Provides support for ehcache
    implementation("com.appmattus.layercache:layercache-ehcache:<latest-version>")

    // Provides support for cache2k
    implementation("com.appmattus.layercache:layercache-cache2k:<latest-version>")

    // Provides LruCache & DiskLruCache support for Android
    implementation("com.appmattus.layercache:layercache-android:<latest-version>")

    // Provides one-line String encryption for Android
    implementation("com.appmattus.layercache:layercache-android-encryption:<latest-version>")

    // Provides conversion from Cache into LiveData for Android
    implementation("com.appmattus.layercache:layercache-android-livedata:<latest-version>")
}

Contributing

Please fork this repository and contribute back using pull requests.

All contributions, large or small, major features, bug fixes, additional language translations, unit/integration tests are welcomed.

License License

Copyright 2020 Appmattus Limited

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.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].