{"id":18981105,"url":"https://github.com/appmattus/layercache","last_synced_at":"2025-08-20T01:31:04.435Z","repository":{"id":54373455,"uuid":"107506418","full_name":"appmattus/layercache","owner":"appmattus","description":"Caching made simple for Android and Java.","archived":false,"fork":false,"pushed_at":"2022-01-04T23:18:22.000Z","size":728,"stargazers_count":179,"open_issues_count":1,"forks_count":19,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-12-11T08:51:32.015Z","etag":null,"topics":["android","cache","hacktoberfest","kotlin","layercache"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/appmattus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["mattmook"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2017-10-19T06:24:43.000Z","updated_at":"2024-09-12T09:14:40.000Z","dependencies_parsed_at":"2022-08-13T13:41:02.609Z","dependency_job_id":null,"html_url":"https://github.com/appmattus/layercache","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appmattus%2Flayercache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appmattus%2Flayercache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appmattus%2Flayercache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appmattus%2Flayercache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appmattus","download_url":"https://codeload.github.com/appmattus/layercache/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230382858,"owners_count":18216854,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","cache","hacktoberfest","kotlin","layercache"],"created_at":"2024-11-08T16:08:42.531Z","updated_at":"2024-12-19T05:07:04.361Z","avatar_url":"https://github.com/appmattus.png","language":"Kotlin","funding_links":["https://github.com/sponsors/mattmook"],"categories":["缓存库"],"sub_categories":[],"readme":"# layercache\n\n![CI](https://github.com/appmattus/layercache/workflows/CI/badge.svg?branch=main)\n[![codecov](https://codecov.io/gh/appmattus/layercache/branch/main/graph/badge.svg)](https://codecov.io/gh/appmattus/layercache)\n\nCaching made simple for Android and Kotlin.\n\nAn important component of building [offline-first architectures](https://developer.android.com/develop/quality-guidelines/building-for-billions-connectivity.html#network-duplicate)\nis to implement caching.\n\n\u003e An offline-first architecture initially tries to fetch data from local storage\n\u003e and, failing that, requests the data from the network. After being retrieved\n\u003e from the network, the data is cached locally for future retrieval. This helps\n\u003e to ensure that network requests for the same piece of data only occur\n\u003e once—with subsequent requests satisfied locally.\n\n![](README/cache-flowchart.png)\n\nAt its simplest, a cache is nothing more than a key-value store with a getter\nand setter.\n\n```kotlin\ninterface Cache\u003cKey : Any, Value : Any\u003e {\n    suspend fun get(key: Key): Value?\n    suspend fun set(key: Key, value: Value)\n}\n```\n\nThe real power comes when we are able to compose two caches into a new cache. A\nmemory cache should have a single responsibility to store data in memory, and a\ndisk cache a single responsibility to store data on disk.\n\n```kotlin\nval cache = memoryCache.compose(diskCache)\n```\n\nFor more details read [Caching made simple on Android](https://medium.com/@appmattus/caching-made-simple-on-android-d6e024e3726b)\nor watch the talk from [droidcon London 2017](https://skillsmatter.com/skillscasts/11062-lightning-talk-building-composable-caches-on-android).\n\n## Getting started\n\n### Base module\n\n```kotlin\nimplementation(\"com.appmattus.layercache:layercache:\u003clatest-version\u003e\")\n```\n\n#### Composing two caches\n\nWhen `get` is called on the composed cache, the first cache will be checked and\nif available returned. If not the second cache will be checked and if available\nset in the first cache and returned.\n\n```kotlin\ncomposedCache: Cache\u003cKey, Value\u003e = firstCache.compose(secondCache)\n```\n\n#### Transforming values\n\nTransform values between data types. This can be used for serialisation and\nencryption amongst other things. i.e.\n`Cache\u003cKey, Value\u003e → Cache\u003cKey, MappedValue\u003e`\n\nFor two way transformations:\n\n```kotlin\nval cache: Cache\u003cKey, Value\u003e = ...\nval valueTransform: Cache\u003cKey, MappedValue\u003e = cache.valueTransform(transform, inverseTransform)\n\n// or\n\nval cache: Cache\u003cKey, Value\u003e = ...\nval valueTransform: Cache\u003cKey, MappedValue\u003e = cache.valueTransform(TwoWayTransform)\n```\n\nOne way transforms return a Fetcher instead of Cache, but otherwise work in the\nsame way. A Fetcher simply implements no-op for `set` and `evict`.\n\n```kotlin\nval fetcher: Fetcher\u003cKey, Value\u003e = ...\nval valueTransform: Cache\u003cKey, MappedValue\u003e = cache.valueTransform(transform)\n\n// or\n\nval fetcher: Fetcher\u003cKey, Value\u003e = ...\nval valueTransform: Cache\u003cKey, MappedValue\u003e = cache.valueTransform(OneWayTransform)\n```\n\n##### Encrypting values\n\n```kotlin\nimplementation(\"com.appmattus.layercache:layercache-android-encryption:\u003clatest-version\u003e\")\n```\n\nThere is support for encrypting string keys and string values (in any cache) on\nAndroid with the `layercache-android-encryption` module. The library is using\n[Google Tink](https://github.com/google/tink) to perform the encryption using\nAES-256 SIV for keys and AES-256 GCM for values.\n\n```kotlin\n// Encrypt key and value when both are strings\nval cache: Cache\u003cString, String\u003e = ...\nval encryptedCache = cache.encrypt(context)\n\n// Both key and value stored encrypted in `cache`\nencryptedCache.set(\"hello\", \"world\")\n\n// Encrypt values only when just the value is a string\nval cache: Cache\u003cKey, String\u003e = ...\nval encryptedCache = cache.encryptValues(context)\n\n// Just value stored encrypted in `cache`\nencryptedCache.set(\"hello\", \"world\")\n```\n\n#### Transforming keys\n\nTransform keys to a different data type. i.e.\n`Cache\u003cKey, Value\u003e → Cache\u003cMappedKey, Value\u003e`\n\n```kotlin\nval cache: Cache\u003cKey, Value\u003e = ...\nval keyTransform: Cache\u003cMappedKey, Value\u003e = cache.keyTransform(transform)\n\n// or\n\nval cache: Cache\u003cKey, Value\u003e = ...\nval keyTransform: Cache\u003cMappedKey, Value\u003e = cache.keyTransform(OneWayTransform)\n```\n\n#### Re-using in flight requests\n\nIf a get request is already in flight then this ensures the original request is\nreturned. This may be necessary for disk and network requests along with\ntransformations that take time to execute.\n\n```kotlin\nval newCache: Cache\u003cKey, Value\u003e = cache.reuseInflight()\n```\n\n### Serializer module\n\n```kotlin\nimplementation(\"com.appmattus.layercache:layercache-serializer:\u003clatest-version\u003e\")\n```\n\nConfigures a transformation from JSON to a serialisable data class and\nvice-versa. This is useful to store data on disk or in a database.\ni.e. `Cache\u003cKey, String\u003e → Cache\u003cKey, Value\u003e`\n\n```kotlin\n@Serialize\ndata class Value(val value)\n\nval cache: Cache\u003cKey, String\u003e = ...\n\nval objectCache: Cache\u003cKey, Value\u003e = cache.jsonSerializer(Value::class.serializer())\n\n```\n\n### Android base module\n\n```kotlin\nimplementation(\"com.appmattus.layercache:layercache-android:\u003clatest-version\u003e\")\n```\n\n#### LruCache\n\n```kotlin\nval memoryCache: Cache\u003cKey, Value\u003e = Cache.createLruCache(maxSize: Int)\n\n// or\n\nval memoryCache: Cache\u003cKey, Value\u003e = Cache.fromLruCache(...)\n```\n\n#### DiskLruCache\n\n```kotlin\nval diskCache: Cache\u003cString, String\u003e = Cache.createDiskLruCache(directory: File, maxSize: Long)\n\n// or\n\nval diskCache: Cache\u003cString, String\u003e = Cache.fromDiskLruCache(...)\n```\n\n#### SharedPreferences\n\nCreate a cache backed by shared preferences.\n\n```kotlin\nval sharedPreferences = context.getSharedPreferences(\"filename\", Context.MODE_PRIVATE)\n\nval anyValueCache: Cache\u003cString, Any\u003e =\n        sharedPreferences.asCache()\n\nval stringValueCache: Cache\u003cString, String\u003e =\n        sharedPreferences.asStringCache()\n\nval stringSetValueCache: Cache\u003cString, Set\u003cString\u003e\u003e =\n        sharedPreferences.asStringSetCache()\n\nval intValueCache: Cache\u003cString, Int\u003e =\n        sharedPreferences.asIntCache()\n\nval floatValueCache: Cache\u003cString, Float\u003e =\n        sharedPreferences.asFloatCache()\n\nval booleanValueCache: Cache\u003cString, Boolean\u003e =\n        sharedPreferences.asBooleanCache()\n\nval longValueCache: Cache\u003cString, Long\u003e =\n        sharedPreferences.asLongCache()\n```\n\n##### EncryptedSharedPreferences\n\n```kotlin\nimplementation(\"androidx.security:security-crypto:\u003clatest-version\u003e\")\n```\n\nUse Jetpack Security to provide a cache backed by encrypted shared preferences\nwhere keys and values are both encrypted.\n\n```kotlin\n\nval masterKey = MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()\n\nval sharedPreferences = EncryptedSharedPreferences.create(\n    context,\n    \"filename\",\n    masterKey,\n    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,\n    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM\n)\n\nval anyValueCache: Cache\u003cString, Any\u003e =\n        sharedPreferences.asCache()\n\nval stringValueCache: Cache\u003cString, String\u003e =\n        sharedPreferences.asStringCache()\n\nval stringSetValueCache: Cache\u003cString, Set\u003cString\u003e\u003e =\n        sharedPreferences.asStringSetCache()\n\nval intValueCache: Cache\u003cString, Int\u003e =\n        sharedPreferences.asIntCache()\n\nval floatValueCache: Cache\u003cString, Float\u003e =\n        sharedPreferences.asFloatCache()\n\nval booleanValueCache: Cache\u003cString, Boolean\u003e =\n        sharedPreferences.asBooleanCache()\n\nval longValueCache: Cache\u003cString, Long\u003e =\n        sharedPreferences.asLongCache()\n```\n\n### Android LiveData module\n\n```kotlin\nimplementation(\"com.appmattus.layercache:layercache-android-livedata:\u003clatest-version\u003e\")\n```\n\nGiven a cache we can convert it for use with LiveData. This makes the getter\nreturn a `LiveDataResult` which can be one of `Loading`, `Success` or `Failure`.\n\n```kotlin\nval liveDataCache = cache.toLiveData()\n\nliveDataCache.get(\"key\").observe(owner) { liveDataResult -\u003e\n    when (liveDataResult) {\n        is LiveDataResult.Loading -\u003e {\n            // display in progress\n        }\n        is LiveDataResult.Success -\u003e {\n            // display liveDataResult.value\n        }\n        is LiveDataResult.Failure -\u003e {\n            // display liveDataResult.exception\n        }\n    }\n}\n\n```\n\n## Download [![Maven Central](https://img.shields.io/maven-central/v/com.appmattus.layercache/layercache)](https://search.maven.org/search?q=g:com.appmattus.layercache)\n\n```kotlin\ndependencies {\n    implementation(\"com.appmattus.layercache:layercache:\u003clatest-version\u003e\")\n\n    // To use with the Kotlin serializer\n    implementation(\"com.appmattus.layercache:layercache-serializer:\u003clatest-version\u003e\")\n\n    // Provides support for ehcache\n    implementation(\"com.appmattus.layercache:layercache-ehcache:\u003clatest-version\u003e\")\n\n    // Provides support for cache2k\n    implementation(\"com.appmattus.layercache:layercache-cache2k:\u003clatest-version\u003e\")\n\n    // Provides LruCache \u0026 DiskLruCache support for Android\n    implementation(\"com.appmattus.layercache:layercache-android:\u003clatest-version\u003e\")\n\n    // Provides one-line String encryption for Android\n    implementation(\"com.appmattus.layercache:layercache-android-encryption:\u003clatest-version\u003e\")\n\n    // Provides conversion from Cache into LiveData for Android\n    implementation(\"com.appmattus.layercache:layercache-android-livedata:\u003clatest-version\u003e\")\n}\n```\n\n## Contributing\n\nPlease fork this repository and contribute back using [pull requests](https://github.com/appmattus/layercache/pulls).\n\nAll contributions, large or small, major features, bug fixes, additional\nlanguage translations, unit/integration tests are welcomed.\n\n## License [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n\nCopyright 2020 Appmattus Limited\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappmattus%2Flayercache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappmattus%2Flayercache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappmattus%2Flayercache/lists"}