Limit lifetime of memory content cache
This commit is contained in:
@@ -1,5 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.core.cache
|
|
||||||
|
|
||||||
import androidx.collection.LruCache
|
|
||||||
|
|
||||||
class DeferredLruCache<T>(maxSize: Int) : LruCache<ContentCache.Key, SafeDeferred<T>>(maxSize)
|
|
||||||
33
app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringLruCache.kt
vendored
Normal file
33
app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringLruCache.kt
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package org.koitharu.kotatsu.core.cache
|
||||||
|
|
||||||
|
import androidx.collection.LruCache
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class ExpiringLruCache<T>(
|
||||||
|
val maxSize: Int,
|
||||||
|
private val lifetime: Long,
|
||||||
|
private val timeUnit: TimeUnit,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val cache = LruCache<ContentCache.Key, ExpiringValue<T>>(maxSize)
|
||||||
|
|
||||||
|
operator fun get(key: ContentCache.Key): T? {
|
||||||
|
val value = cache.get(key) ?: return null
|
||||||
|
if (value.isExpired) {
|
||||||
|
cache.remove(key)
|
||||||
|
}
|
||||||
|
return value.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(key: ContentCache.Key, value: T) {
|
||||||
|
cache.put(key, ExpiringValue(value, lifetime, timeUnit))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
cache.evictAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun trimToSize(size: Int) {
|
||||||
|
cache.trimToSize(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringValue.kt
vendored
Normal file
34
app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringValue.kt
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package org.koitharu.kotatsu.core.cache
|
||||||
|
|
||||||
|
import android.os.SystemClock
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class ExpiringValue<T>(
|
||||||
|
private val value: T,
|
||||||
|
lifetime: Long,
|
||||||
|
timeUnit: TimeUnit,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val expiresAt = SystemClock.elapsedRealtime() + timeUnit.toMillis(lifetime)
|
||||||
|
|
||||||
|
val isExpired: Boolean
|
||||||
|
get() = SystemClock.elapsedRealtime() >= expiresAt
|
||||||
|
|
||||||
|
fun get(): T? = if (isExpired) null else value
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as ExpiringValue<*>
|
||||||
|
|
||||||
|
if (value != other.value) return false
|
||||||
|
return expiresAt == other.expiresAt
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = value?.hashCode() ?: 0
|
||||||
|
result = 31 * result + expiresAt.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import android.content.res.Configuration
|
|||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class MemoryContentCache(application: Application) : ContentCache, ComponentCallbacks2 {
|
class MemoryContentCache(application: Application) : ContentCache, ComponentCallbacks2 {
|
||||||
|
|
||||||
@@ -13,8 +14,8 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall
|
|||||||
application.registerComponentCallbacks(this)
|
application.registerComponentCallbacks(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val detailsCache = DeferredLruCache<Manga>(4)
|
private val detailsCache = ExpiringLruCache<SafeDeferred<Manga>>(4, 5, TimeUnit.MINUTES)
|
||||||
private val pagesCache = DeferredLruCache<List<MangaPage>>(4)
|
private val pagesCache = ExpiringLruCache<SafeDeferred<List<MangaPage>>>(4, 10, TimeUnit.MINUTES)
|
||||||
|
|
||||||
override val isCachingEnabled: Boolean = true
|
override val isCachingEnabled: Boolean = true
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun putDetails(source: MangaSource, url: String, details: SafeDeferred<Manga>) {
|
override fun putDetails(source: MangaSource, url: String, details: SafeDeferred<Manga>) {
|
||||||
detailsCache.put(ContentCache.Key(source, url), details)
|
detailsCache[ContentCache.Key(source, url)] = details
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getPages(source: MangaSource, url: String): List<MangaPage>? {
|
override suspend fun getPages(source: MangaSource, url: String): List<MangaPage>? {
|
||||||
@@ -31,7 +32,7 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun putPages(source: MangaSource, url: String, pages: SafeDeferred<List<MangaPage>>) {
|
override fun putPages(source: MangaSource, url: String, pages: SafeDeferred<List<MangaPage>>) {
|
||||||
pagesCache.put(ContentCache.Key(source, url), pages)
|
pagesCache[ContentCache.Key(source, url)] = pages
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) = Unit
|
override fun onConfigurationChanged(newConfig: Configuration) = Unit
|
||||||
@@ -43,17 +44,17 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall
|
|||||||
trimCache(pagesCache, level)
|
trimCache(pagesCache, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun trimCache(cache: DeferredLruCache<*>, level: Int) {
|
private fun trimCache(cache: ExpiringLruCache<*>, level: Int) {
|
||||||
when (level) {
|
when (level) {
|
||||||
ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL,
|
ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL,
|
||||||
ComponentCallbacks2.TRIM_MEMORY_COMPLETE,
|
ComponentCallbacks2.TRIM_MEMORY_COMPLETE,
|
||||||
ComponentCallbacks2.TRIM_MEMORY_MODERATE -> cache.evictAll()
|
ComponentCallbacks2.TRIM_MEMORY_MODERATE -> cache.clear()
|
||||||
|
|
||||||
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN,
|
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN,
|
||||||
ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
|
ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
|
||||||
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> cache.trimToSize(1)
|
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> cache.trimToSize(1)
|
||||||
|
|
||||||
else -> cache.trimToSize(cache.maxSize() / 2)
|
else -> cache.trimToSize(cache.maxSize / 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user