ref: bbe9c621a38627a8ce44ee46045f586b8e44704c
app/src/main/java/ml/adamsprogs/bimba/datasources/CacheManager.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
package ml.adamsprogs.bimba.datasources import android.content.Context import android.content.SharedPreferences import ml.adamsprogs.bimba.models.Plate import ml.adamsprogs.bimba.models.gtfs.AgencyAndId class CacheManager private constructor(context: Context) { companion object { private var manager: CacheManager? = null fun getCacheManager(context: Context): CacheManager { return if (manager == null) { manager = CacheManager(context) manager!! } else manager!! } val MAX_SIZE = 40 } private var cachePreferences: SharedPreferences = context.getSharedPreferences("ml.adamsprogs.bimba.cachePreferences.cache", Context.MODE_PRIVATE) private var cacheHitsPreferences: SharedPreferences = context.getSharedPreferences("ml.adamsprogs.bimba.cachePreferences.cacheHits", Context.MODE_PRIVATE) private var cache: HashMap<String, Plate> = HashMap() private var cacheHits: HashMap<String, Int> = HashMap() fun keys(): List<Plate> { return cache.map { Plate(Plate.ID( AgencyAndId.convertFromString(it.key.split("@")[0]), AgencyAndId.convertFromString(it.key.split("@")[1].split(">")[0]), it.key.split(">")[1]), null) } } fun hasAll(plates: HashSet<Plate>): Boolean { plates .filterNot { has(it) } .forEach { return false } return true } fun hasAny(plates: HashSet<Plate>): Boolean { plates .filter { has(it) } .forEach { return true } return false } fun has(plate: Plate): Boolean { return cache.containsKey(key(plate)) } fun push(plates: HashSet<Plate>) { val removeNumber = cache.size + plates.size - MAX_SIZE val editor = cachePreferences.edit() val editorCacheHits = cacheHitsPreferences.edit() cacheHits.map { "${it.value}|${it.key}" }.sortedBy { it }.slice(0 until removeNumber).forEach { val key = it.split("|")[1] cache.remove(key) editor.remove(key) } for (plate in plates) { val key = key(plate) cache[key] = plate cacheHits[key] = 0 editor.putString(key, cache[key].toString()) editorCacheHits.putInt(key, 0) } editor.apply() editorCacheHits.apply() } fun push(plate: Plate) { val editorCache = cachePreferences.edit() val editorCacheHits = cacheHitsPreferences.edit() if (cacheHits.size == MAX_SIZE) { val key = cacheHits.minBy { it.value }?.key cache.remove(key) editorCache.remove(key) cacheHits.remove(key) editorCacheHits.remove(key) } val key = key(plate) cache[key] = plate cacheHits[key] = 0 editorCache.putString(key, plate.toString()) editorCacheHits.putInt(key, 0) editorCache.apply() editorCacheHits.apply() } fun get(plates: HashSet<Plate>): HashSet<Plate> { val result = HashSet<Plate>() for (plate in plates) { val value = get(plate) if (value == null) result.add(plate) else result.add(value) } return result } fun get(plate: Plate): Plate? { if (!has(plate)) return null val key = key(plate) val hits = cacheHits[key] if (hits != null) cacheHits[key] = hits + 1 return cache[key] } fun recreate(stopDeparturesByPlates: Set<Plate>) { stopDeparturesByPlates.forEach { cache[key(it)] = it } } init { cache = cacheFromString(cachePreferences.all) @Suppress("UNCHECKED_CAST") cacheHits = cacheHitsPreferences.all as HashMap<String, Int> } private fun cacheFromString(preferences: Map<String, *>): HashMap<String, Plate> { val result = HashMap<String, Plate>() for ((key, value) in preferences.entries) { result[key] = Plate.fromString(value as String) } return result } private fun key(plate: Plate) = "${plate.id.line}@${plate.id.stop}>${plate.id.headsign}" } |