GithubHelp home page GithubHelp logo

yousefbeiruty / coroutinescache Goto Github PK

View Code? Open in Web Editor NEW

This project forked from epam/coroutinescache

0.0 0.0 0.0 264 KB

In mobile development exists solution for caching with RxJava usage, but there is no solutions for Kotlin Coroutines. The project is to provide this functionality to mobile community.

License: Apache License 2.0

Kotlin 99.41% Shell 0.59%

coroutinescache's Introduction

CoroutinesCache

Build Status

Preview

The goal of this library is simple: caching your data models like Picasso caches your images, with no effort at all.

Every Android application is a client application, which means it does not make sense to create and maintain a database just for caching data.

Plus, the fact that you have some sort of legendary database for persisting your data does not solves by itself the real challenge: to be able to configure your caching needs in a flexible and simple way.

Inspired by Retrofit api, CoroutinesCache is a reactive caching library for Android and Kotlin which turns your caching needs.

To get full information about how library works follow next article:

https://proandroiddev.com/caching-with-kotlin-coroutines-7d819276c820

Note

Coroutines Cache works only on kotlin-coroutines:0.26.1 and above.

Getting started

Library is located in jcenter, add jcenter repository in main gradle file

allprojects {
  repositories {
    ...
    jcenter()
  }
}

Grab via Gradle:

  implementation 'com.epam.coroutinecache:coroutinecache:0.9.6'

or Maven:

  <dependency>
    <groupId>com.epam.coroutinecache</groupId>
    <artifactId>coroutinecache</artifactId>
    <version>0.9.6</version>
    <type>pom</type>
  </dependency>

Usage

To start use cache you need to create CoroutinesCache object:

val coroutinesCache = CoroutinesCache(cacheParams: CacheParams, scope: CoroutineScope)

CacheParams defines cache location, json mapper and persistence size in Mb.

First param of CacheParams is max size that could be saved in persistence in Mb.

Second param is JsonMapper interface that provides one of several implementation: GsonMapper, JacksonMapper, MoshiMapper. For each of those mappers you need to add appropriate dependency in build.gradle file.

Last param is directory where cache files will be stored. Be sure that directory exists and you has write permission there, otherwise you will get IllegalStateException

class CacheParams (maxPersistenceCacheMB: Int, mapper: JsonMapper, directory: File)

Next step you need to create an interface with functions that will describe data, which should be stored. For each function you can add params by next annotations:

  1. @ProviderKey(key: String, entryClass: EntryClass) - key that will be used for saving data, entryClass it is an another annotation @EntryClass(rawType: KClass<*>, vararg typeParams: EntryClass = []) that used to specify value's type needed for serialization/deserialization (to avoid obtaining type through reflection). typeParams used when you need parameterized type, such annotation for list should looks like: EntryClass(List::class, EntryClass(Data::class))
  2. @LifeTime(value: Long, timeUnit: TimeUnit) - value describes how long record should be stored in memory or persistence. If this annotation isn't set, record will be stored without time limit
  3. @Expirable - Set expirable param to true. If this annotation isn't set it means that record could be deleted from persistence, even it hasn't reached life limit in persistence low memory case.
  4. @UseIfExpired - If this annotation is set it means that data will be retrieved from cache even if record reached its lifetime. Could be used only once, after getting, record will be deleted from cache.

Note: In cases when data can be requested without any parameters you may use a method that should be a suspend function containing only one param that is also a suspend function without params that returns type T. It's result will be stored in the cache. And function's return value also should be In case, when you data request call requires some parameters and also you want to store data with different keys that depend on call parameters, then you should use a suspend method that takes an implementation of ParameterizedDataProvider interface. In that case data will be stored under modified key that is controlled by your implementation of parameterizeKey method.

To connect interface and CoroutinesCache and your interface just call CoroutinesCache.using(YourInterface::class.java). This method will return interface instance. To save and get data from cache just call methods from returned instance of your interface.

Example 1 (no parameters)

CacheProviders

interface CacheProviders {
    @ProviderKey("TestKey", EntryClass(Data::class))
    @LifeTime(value = 1L, unit = TimeUnit.MINUTES)
    @Expirable
    @UseIfExpired
    suspend fun getData(dataProvider: suspend () -> Data): Data
}

Repository

class Repository (private val cacheDirectory: File) {
     private val coroutinesCache = CoroutinesCache(CacheParams(10, GsonMapper(), cacheDirectory))
     private val restApi = Retrofit...create(RestApi::class.java)
     private val cacheProviders = coroutinesCache.using(CacheProviders::class.java)
     
     suspend fun getData(): Data = cacheProviders.getData(restApi::getData)
}

MainActivity

class MainActivity : AppCompatActivity() {
    private val persistence by lazy { Repository(cacheDir) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        GlobalScope.launch (Dispatchers.Main) {
            val data = persistence.getData()
            messageView.text = data.toString()
        }
    }
}

Example 2 (with parameters)

CacheProviders

interface CacheProviders {
    @ProviderKey("BaseKey", EntryClass(Data::class))
    @LifeTime(value = 1L, unit = TimeUnit.MINUTES)
    @Expirable
    @UseIfExpired
    suspend fun getParameterizedData(provider: ParameterizedDataProvider<Data>): Data
}

Repository

class Repository (private val cacheDirectory: File) {
     private val coroutinesCache = CoroutinesCache(CacheParams(10, GsonMapper(), cacheDirectory))
     private val restApi = Retrofit...create(RestApi::class.java)
     private val cacheProviders = coroutinesCache.using(CacheProviders::class.java)

     suspend fun getParametrizedData(search: String): Data = cacheProviders.getParameterizedData(DataProviderImpl())

     private inner class DataProviderImpl(private val search: String) : ParameterizedDataProvider<Data> {

          override suspend fun getData(): Data = restApi.getParameterizedData(search)

          override fun parameterizeKey(baseKey: String): String = "${baseKey}_$search"
     }
}

MainActivity

class MainActivity : AppCompatActivity() {
    private val persistence by lazy { Repository(cacheDir) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        GlobalScope.launch (Dispatchers.Main) {
            val data = persistence.getParameterizedData("Hello world!")
            messageView.text = data.toString()
        }
    }
}

To see full example, check app module in this repository.

ProGuard

Do not forget to keep your own data classes in proguard rules. For example, add this line for 'Data' class that is being cached with this library:

# Keep all of your data classes that are stored in CoroutineCache
-keep class com.epam.example.coroutinescache.Data { *; }

Also, please add following instructions so that CoroutineCache may work properly:

# ProGuard instructions that are required for CoroutineCache to work properly
-keepclassmembers enum com.epam.coroutinecache.core.Source {
    public *;
}

coroutinescache's People

Contributors

ahulyk avatar alexeykorshun avatar dartlexx avatar ivansakharovskii avatar likeanyan avatar prudhvir3ddy avatar vvsevolodovich avatar

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.