Created
July 8, 2018 15:06
-
-
Save khanlou/cd87b1dbc532bd90e8c11c8e9d675769 to your computer and use it in GitHub Desktop.
Simple image fetching and caching example. Intended for Firebase but the fetching architecture could be abstracted out. Dependent on `com.jakewharton.disklrucache.DiskLruCache`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package amal.global.amal | |
import android.content.Context | |
import android.graphics.Bitmap | |
import android.graphics.BitmapFactory | |
import android.util.LruCache | |
import com.google.firebase.storage.StorageReference | |
import com.jakewharton.disklrucache.DiskLruCache | |
import java.io.File | |
import java.security.MessageDigest | |
class ImageFetcher(val context: Context) { | |
private val memoryCache = ImageMemoryCache(context) | |
private val diskCache = ImageDiskCache(context) | |
fun fetchImage(firebaseReference: StorageReference): Promise<Bitmap> { | |
val key = firebaseReference.toString() | |
memoryCache.get(key)?.let { | |
return@fetchImage Promise(it) | |
} | |
diskCache.get(key)?.let { | |
memoryCache.set(key, it) | |
return@fetchImage Promise(it) | |
} | |
return firebaseReference | |
.getBytesPromise(Long.MAX_VALUE) | |
.flatMap { byteArray -> | |
byteArray.decodeBitmap() | |
} | |
.then { bitmap -> | |
memoryCache.set(key, bitmap) | |
diskCache.set(key, bitmap) | |
} | |
} | |
} | |
class ImageDiskCache(val context: Context) { | |
private val cachePath = context.cacheDir.path | |
private val cacheFile = File(cachePath + File.separator + "images") | |
val cache = DiskLruCache.open(cacheFile, 1, 1, 10*1024*1024 /* 10 megabytes */) | |
fun filenameForKey(key: String): String { | |
return MessageDigest | |
.getInstance("SHA-1") | |
.digest(key.toByteArray()) | |
.joinToString(separator = "", transform = { Integer.toHexString(0xFF and it.toInt()) }) | |
} | |
fun get(key: String): Bitmap? { | |
try { | |
val filename = filenameForKey(key) | |
val inputStream = cache.get(filename).getInputStream(0) | |
return BitmapFactory.decodeStream(inputStream) | |
} catch (e: Exception) { | |
return null | |
} | |
} | |
fun set(key: String, bitmap: Bitmap) { | |
val filename = filenameForKey(key) | |
val snapshot = cache.get(filename) | |
if (snapshot == null) { | |
val editor = cache.edit(filename) | |
val outputStream = editor.newOutputStream(0) | |
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) | |
editor.commit() | |
outputStream.close() | |
} else { | |
snapshot.getInputStream(0).close() | |
} | |
} | |
} | |
class ImageMemoryCache(context: Context) { | |
private val maxMemory = Runtime.getRuntime().maxMemory().toInt() | |
private val cacheSize = maxMemory / 8 | |
private val cache = object: LruCache<String, Bitmap>(cacheSize) { | |
override fun sizeOf(key: String?, bitmap: Bitmap?): Int { | |
return bitmap?.let { it.allocationByteCount } ?: 0 | |
} | |
} | |
fun get(key: String): Bitmap? { | |
return cache.get(key) | |
} | |
fun set(key: String, bitmap: Bitmap) { | |
cache.put(key, bitmap) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment