Kotlin实现Glide/Coil图/视频加载框架(二)
在 https://blog.csdn.net/zhangphil/article/details/150206845 基础上抽象封装,实现一种总体的图视频加载框架。增加磁盘缓存读写策略。
Kotlin
enum class DiskCachePolicy {
READ_ONLY,//只读缓存,不写缓存
WRITE_ONLY,//跳过缓存读,只缓存写
READ_WRITE,//既缓存读,又缓存写
NONE //不读缓存,也不写缓存. 不使用任何缓存策略。
}
Kotlin
import kotlin.random.Random
open class Fetcher<D : Item, R : Result?> {
companion object {
const val TAG = "Fetcher"
}
private var mItem: D? = null
private var mDiskCachePolicy = DiskCachePolicy.NONE
constructor(item: D) {
mItem = item
}
fun fetch(): R? {
println("$TAG 缓存策略=${getDiskCachePolicy()}")
var result: R? = null
when (getDiskCachePolicy()) {
DiskCachePolicy.NONE -> {
result = readRaw()
}
DiskCachePolicy.READ_ONLY -> {
val cacheExist = checkDiskCacheExist()
println("$TAG $mItem 本地缓存状态=$cacheExist")
if (cacheExist) {
result = readCache()
}
if (result == null) {
result = readRaw()
}
}
DiskCachePolicy.WRITE_ONLY -> {
result = readRaw()
if (result != null) {
val cacheExist = checkDiskCacheExist()
println("$TAG $mItem 本地缓存状态=$cacheExist")
if (!cacheExist) {
writeCache(mItem, result)
}
}
}
DiskCachePolicy.READ_WRITE -> {
val cacheExist = checkDiskCacheExist()
println("$TAG $mItem 本地缓存状态=$cacheExist")
if (cacheExist) {
result = readCache()
}
if (result == null) {
result = readRaw()
}
if (result != null) {
if (!cacheExist) {
writeCache(mItem, result)
}
}
}
else -> {
TODO()
}
}
return result
}
open fun readRaw(): R? {
val result = longTimeRawFileIoRead(mItem!!)
return result as R?
}
private fun readCache(): R? {
if (Random.nextBoolean()) {
//特意制造读缓存失败的场景,测试架构的适应性和鲁棒性。
println("$TAG $mItem 读本地缓存发生异常")
return null
} else {
val result = longTimeCacheFileIoRead(mItem!!)
return result as R?
}
}
//假设这里是耗时的IO读文件任务,把缓存在文件里面的数据读出来.
private fun longTimeCacheFileIoRead(item: D): R? {
val result = Result()
result.req = item
result.data = System.currentTimeMillis()
Thread.sleep(100)
println("$TAG $item 读取缓存数据 $result")
return result as R?
}
//模拟耗时的IO读文件任务,把本地原始文件里面的数据读出来.
private fun longTimeRawFileIoRead(item: D): R? {
val result = Result()
result.req = item
result.data = System.currentTimeMillis()
Thread.sleep(1000)
println("$TAG $item 读原始数据 $result")
return result as R?
}
private fun writeCache(item: D?, result: R?) {
longTimeCacheFileWrite(item, result)
}
//假设这里是长时间的耗时写缓存文件操作。
private fun longTimeCacheFileWrite(item: D?, result: R?) {
Thread.sleep(100)
println("$TAG $item $result longTimeCacheFileWrite() 写入本地缓存")
}
fun setDiskCachePolicy(diskCachePolicy: DiskCachePolicy) {
mDiskCachePolicy = diskCachePolicy
}
open fun getDiskCachePolicy(): DiskCachePolicy {
return mDiskCachePolicy
}
//模拟检查本地缓存是否存在.
//这一过程需要检查本地缓存文件中是否存在文件缓存,耗时操作。
private fun checkDiskCacheExist(): Boolean {
Thread.sleep(10)
val exist = Random.nextBoolean()
return exist
}
}
Kotlin
class GifFetcher : Fetcher<Item, Result?> {
constructor(item: GifItem) : super(item) {
}
}
Kotlin
class GifItem : Item {
constructor() {
type = GIF
}
}
Kotlin
open class Item : Any {
companion object {
const val VIDEO = 1
const val GIF = 2
}
var type = -1
var timestamp = System.nanoTime()
constructor() {
}
override fun toString(): String {
return "Item(type=$type, timestamp=$timestamp)"
}
}
Kotlin
class Loader {
companion object {
private var mLoader: Loader? = null
fun build(): Loader {
val loader = Loader()
mLoader = loader
return mLoader!!
}
}
private var mListener: Listener? = null
private var mFetcher: Fetcher<Item, Result?>? = null
constructor() {
}
fun setFetch(fetcher: Fetcher<Item, Result?>): Loader {
mFetcher = fetcher
return mLoader!!
}
fun setCachePolicy(cachePolicy: DiskCachePolicy): Loader {
mFetcher?.setDiskCachePolicy(cachePolicy)
return mLoader!!
}
fun setListener(listener: Listener): Loader {
mListener = listener
return mLoader!!
}
fun load() {
val result = mFetcher?.fetch()
mListener?.onSuccess(result)
}
interface Listener {
fun onSuccess(result: Result?) {}
fun onFail(e: Exception) {}
}
}
Kotlin
class Result {
var req: Item? = null
var tag: Any? = null
var data: Any? = null
override fun toString(): String {
return "Result(req=$req, tag=$tag, data=$data)"
}
}
Kotlin
class VideoFetcher : Fetcher<Item, Result?> {
companion object {
const val TAG = "VideoFetcher"
}
private var mItem: VideoItem? = null
constructor(item: VideoItem) : super(item) {
mItem = item
}
override fun readRaw(): Result? {
val result = Result()
result.req = mItem
println("$TAG $mItem 读原始数据")
return result
}
override fun getDiskCachePolicy(): DiskCachePolicy {
return DiskCachePolicy.READ_WRITE
}
}
Kotlin
class VideoItem : Item {
constructor(){
type = VIDEO
}
}
测试的main函数:
Kotlin
import kotlin.random.Random
fun main() {
//测试
(0..3).forEach { _ ->
Loader.build()
.setFetch(GifFetcher(GifItem()))
.setCachePolicy(getDiskCachePolicy())
.setListener(object : Loader.Listener {
override fun onSuccess(result: Result?) {
println("main $result ${result?.req}")
}
}).load()
println("---")
}
Loader.build()
.setFetch(VideoFetcher(VideoItem()))
.setListener(object : Loader.Listener {
override fun onSuccess(result: Result?) {
println("main $result ${result?.req}")
}
}).load()
}
//随机生成测试的缓存策略
private fun getDiskCachePolicy(): DiskCachePolicy {
val rand = Random.nextInt(DiskCachePolicy.entries.size)
var diskCachePolicy = DiskCachePolicy.NONE
when (rand) {
DiskCachePolicy.READ_ONLY.ordinal -> {
diskCachePolicy = DiskCachePolicy.READ_ONLY
}
DiskCachePolicy.WRITE_ONLY.ordinal -> {
diskCachePolicy = DiskCachePolicy.WRITE_ONLY
}
DiskCachePolicy.READ_WRITE.ordinal -> {
diskCachePolicy = DiskCachePolicy.READ_WRITE
}
DiskCachePolicy.NONE.ordinal -> {
diskCachePolicy = DiskCachePolicy.NONE
}
else -> {
}
}
return diskCachePolicy
}
运行输出:
Fetcher 缓存策略=READ_WRITE
Fetcher Item(type=2, timestamp=884027990900) 本地缓存状态=true
Fetcher Item(type=2, timestamp=884027990900) 读取缓存数据 Result(req=Item(type=2, timestamp=884027990900), tag=null, data=1768442150276)
main Result(req=Item(type=2, timestamp=884027990900), tag=null, data=1768442150276) Item(type=2, timestamp=884027990900)
Fetcher 缓存策略=READ_ONLY
Fetcher Item(type=2, timestamp=884169920800) 本地缓存状态=false
Fetcher Item(type=2, timestamp=884169920800) 读原始数据 Result(req=Item(type=2, timestamp=884169920800), tag=null, data=1768442150400)
main Result(req=Item(type=2, timestamp=884169920800), tag=null, data=1768442150400) Item(type=2, timestamp=884169920800)
Fetcher 缓存策略=WRITE_ONLY
Fetcher Item(type=2, timestamp=885198545700) 读原始数据 Result(req=Item(type=2, timestamp=885198545700), tag=null, data=1768442151413)
Fetcher Item(type=2, timestamp=885198545700) 本地缓存状态=false
Fetcher Item(type=2, timestamp=885198545700) Result(req=Item(type=2, timestamp=885198545700), tag=null, data=1768442151413) longTimeCacheFileWrite() 写入本地缓存
main Result(req=Item(type=2, timestamp=885198545700), tag=null, data=1768442151413) Item(type=2, timestamp=885198545700)
Fetcher 缓存策略=READ_WRITE
Fetcher Item(type=2, timestamp=886325747400) 本地缓存状态=true
Fetcher Item(type=2, timestamp=886325747400) 读取缓存数据 Result(req=Item(type=2, timestamp=886325747400), tag=null, data=1768442152556)
main Result(req=Item(type=2, timestamp=886325747400), tag=null, data=1768442152556) Item(type=2, timestamp=886325747400)
Fetcher 缓存策略=READ_WRITE
Fetcher Item(type=1, timestamp=886448708000) 本地缓存状态=true
Fetcher Item(type=1, timestamp=886448708000) 读本地缓存发生异常
VideoFetcher Item(type=1, timestamp=886448708000) 读原始数据
main Result(req=Item(type=1, timestamp=886448708000), tag=null, data=null) Item(type=1, timestamp=886448708000)
Process finished with exit code 0
相关:https://blog.csdn.net/zhangphil/article/details/150206845