Android数据缓存框架 - 内存数据载体从LiveData到StateFlow

引言:所有成功者的背后,都有一份艰苦的历程,不要只看到了人前的风光,而低估了他们背后所付出的努力。

随着flow到流行度越来越高,有开发者呼吁我使用flow,于是我就如你们所愿,新增了StateFlow作为新的数据载体。当然你仍然可以使用旧版本的LiveData,代码写法略微不同罢了。如果对我的dcache框架设计不是很理解的小伙伴,可以看我的专栏其他文章。

为什么推荐使用StateFlow

如果你非要问我为什么要使用StateFlow?我可以告诉你,因为可以装逼,哈哈,开个玩笑。新技术的流行必然有一部分炒作的部分,但也肯定是有其改进的地方的。要讲StateFlow,就不得不从flow开始说起。flow是属于kotlin语言范畴的,你可以把它当成kotlin协程的一个API。没错,kotlin语言的野心就是要做跨平台的语言,答案就在这里,LiveData是android的API,而SharedFlow与StateFlow直接就是Kotlin编程语言级别的,代码复用性更好。

LiveData和StateFlow使用对比

以列表数据模式的Repository为例。从2.1.5开始@Repository注解拆分成了@Repository注解和@ListRepository,所以2.1.4版本你应该使用@Repository注解,而如果说,你使用的是2.1.5及以上版本的dcache库,要使用@ListRepository注解。由于StateFlow在2.2.0版本才开始支持,所以自然要使用@ListRepository注解。 先看StateFlow的写法。

kotlin 复制代码
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 此处省略代码若干行
    lifecycleScope.launchWhenCreated {
        repository.getListFlowData().collect {
            adapter.setTemperatures(it)
        }
    }
}

不要忘了使用协程作用域。 然后我们调用fetchListData()。

kotlin 复制代码
repository.fetchListData(listener = object : OnLoadStateListener {
    override fun onLoad(state: Int) {
        Log.d("WeatherActivity", "数据是否加载成功:${state==0}")
    }
}, description = null)

加载状态监听接口和描述信息可以传null。这个抓取数据方法一经调用,collect代码块就会刷新数据。由于fetchListData()天然就返回的StateFlow,所以你并不一定要分为两步观察数据。而如果你要分为两步,则调用getListFlowData()或getFlowData()。 再看原来LiveData的写法,这次我们不用list模式的Repository,如果要使用,直接配置@Repository注解。

kotlin 复制代码
minutelyRepository.latlng = "116.407526,39.90403"
minutelyRepository.fetchData("按分钟统计天气").observe(this, Observer {
    it?.apply {
        tvCacheMinutely.text = "minutely:${toString()}\n"
    }
})

很明显,fetchData()返回LiveData,直接调用observe()进行数据的观察。简单总结下,API的设计在调用层面具有相似性,所以,无论你使用的是LiveData为数据载体的Repository还是StateFlow的,都是调用fetchData()或fetchListData()更新缓存数据,框架内部自动帮你缓存到数据库,同时常驻在内存并递送给UI层刷新界面。所以你可以专心开发你的业务逻辑,这是不是很棒?

kotlin 复制代码
package com.example.dcache.repository

import android.content.Context
import com.example.dcache.biz.weather.WeatherService
import com.example.dcache.model.WeatherModel
import dora.cache.data.fetcher.OnLoadStateListener
import dora.cache.repository.DoraDatabaseCacheRepository
import dora.cache.repository.Repository
import dora.http.DoraCallback
import dora.http.retrofit.RetrofitManager

@Repository
class WeatherRepository(context: Context) : DoraDatabaseCacheRepository<WeatherModel>(context) {

    var latlng: String = ""

    override fun onLoadFromNetwork(
        callback: DoraCallback<WeatherModel>,
        listener: OnLoadStateListener?
    ) {
        RetrofitManager.getService(WeatherService::class.java).getWeather(latlng).enqueue(callback)
    }
}

最后简单复习一下Repository的写法。详细Demo代码github.com/dora4/DoraC...

框架设计的变化

这是StateFlow的。

kotlin 复制代码
/**
 * 用于网络数据抓取。
 */
interface IFlowDataFetcher<M> {

    /**
     * 清空flow data的数据。
     */
    fun clearData()

    /**
     * 抓取数据的回调。
     */
    fun callback(): DoraCallback<M>

    /**
     * 开始抓取数据。
     */
    fun fetchData(description: String?, listener: OnLoadStateListener? = OnLoadStateListenerImpl()): StateFlow<M?>

    /**
     * 获取flow data。
     */
    fun getFlowData(): StateFlow<M?>
}

这是LiveData的。

kotlin 复制代码
package dora.cache.data.fetcher

import androidx.lifecycle.LiveData
import dora.http.DoraCallback

/**
 * 用于网络数据抓取。
 */
interface IDataFetcher<M> {

    /**
     * 清空livedata的数据。
     */
    fun clearData()

    /**
     * 抓取数据的回调。
     */
    fun callback(): DoraCallback<M>

    /**
     * 开始抓取数据。
     */
    fun fetchData(description: String?, listener: OnLoadStateListener? = OnLoadStateListenerImpl()): LiveData<M?>

    /**
     * 获取livedata。
     */
    fun getLiveData(): LiveData<M?>
}

是不是没啥变化?对的,这就是架构设计的魅力所在,前期架构设计比较到位,所以只需要遵循开闭原则,对扩展开放,对修改关闭。 原先继承BaseRepository的,现在继承BaseFlowRepository的。名字有带Flow单词的,就是StateFlow的。

开源框架支持

笔者写框架和文档不容易,希望你的支持。你的支持是我改进优化最大的动力!

数据缓存dcache框架 github.com/dora4/dcach...

dora框架的开发插件 github.com/dora4/dora-...

dora框架 github.com/dora4/dora

相关推荐
白鲸开源2 小时前
杀疯了!SeaTunnel AI CLI 解锁数据集成新玩法
大数据·人工智能·github
Skylwn3 小时前
保姆级教程之将 GitHub Models 接入 NewAPI
笔记·github
shaoming37763 小时前
浏览器动作开发:地址栏图标点击事件、弹出页面设计
android·mysql·adb
赏金术士4 小时前
Kotlin 协程与挂起函数(Coroutines & suspend)入门到实战
android·开发语言·kotlin
Better Bench4 小时前
Claude Code 学习指南:优秀 GitHub 仓库推荐与进阶路线图
github·claude code·学习指南
逛逛GitHub4 小时前
强烈推荐看看这个演讲,还配套 7 万 Star 的开源 Skill。
github
墨神谕5 小时前
第一次上传本地项目至GitHub
github
泡泡以安6 小时前
Unidbg学习笔记(十三):固定随机干扰项
android·逆向
泡泡以安6 小时前
Unidbg学习笔记(十六):Console Debugger
android·逆向
赏金术士6 小时前
Room + Flow 完整教程(现代 Android 官方方案)
android·kotlin·room·compose