当前位置: 首页 > news >正文

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的写法。

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

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

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注解。

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层刷新界面。所以你可以专心开发你的业务逻辑,这是不是很棒?

package com.example.dcache.repositoryimport 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代码https://github.com/dora4/DoraCacheSample 。

框架设计的变化

这是StateFlow的。

/*** 用于网络数据抓取。*/
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的。

package dora.cache.data.fetcherimport 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?>
}

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

开源框架支持

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

数据缓存dcache框架 https://github.com/dora4/dcache-android

dora框架的开发插件 https://github.com/dora4/dora-studio-plugin

dora框架 https://github.com/dora4/dora

相关文章:

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

引言&#xff1a;所有成功者的背后&#xff0c;都有一份艰苦的历程&#xff0c;不要只看到了人前的风光&#xff0c;而低估了他们背后所付出的努力。 随着flow到流行度越来越高&#xff0c;有开发者呼吁我使用flow&#xff0c;于是我就如你们所愿&#xff0c;新增了StateFlow作…...

多态的好处

使用多态&#xff08;Polymorphism&#xff09;在C中有多个重要的原因&#xff0c;这些原因使得多态成为面向对象编程中不可或缺的一部分。以下是使用多态的一些关键原因&#xff1a; 代码复用和灵活性&#xff1a; 多态允许我们编写可以处理多种类型对象的通用代码。通过使用…...

Java基础语法---Stringjoiner

Stringjoiner 使用需要加入 import java.util.StringJoiner 构造方法: StringJoiner(CharSequence delimiter) 创建一个 StringJoiner 实例&#xff0c;使用指定的分隔符&#xff0c;前缀和后缀默认为空字符串。 StringJoiner(CharSequence delimiter, CharSequence prefix, C…...

大模型中的Tokenizer

在使用GPT 、BERT模型输入词语常常会先进行tokenize 。 tokenize的目标是把输入的文本流&#xff0c;切分成一个个子串&#xff0c;每个子串相对有完整的语义&#xff0c;便于学习embedding表达和后续模型的使用。 一、粒度 三种粒度&#xff1a;word/subword/char word词&a…...

Filebeat进阶指南:核心架构与功能组件的深度剖析

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《洞察之眼&#xff1a;ELK监控与可视化》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是ELK 2、FileBeat在ELK中的角色 二、Fil…...

深度神经网络

深度神经网络&#xff08;Deep Neural Networks&#xff0c;DNNs&#xff09;是机器学习领域中的一项关键技术&#xff0c;它基于人工神经网络的概念&#xff0c;通过构建多层结构来模拟人脑的学习过程。以下是关于深度神经网络的清晰回答&#xff1a; 一、定义与特点 深度神…...

c++【入门】你多大了

时间限制 : 1 秒 内存限制 : 128 MB 一天玩仔跑来问周周你多大了&#xff0c;周周告诉他自己 1010 岁了&#xff0c;玩仔又说自己也是&#xff0c;你听到了这个对话&#xff0c;想用程序显示出两个人的对话内容&#xff0c;现在就来试一试吧。 输入 无 输出 输出三行&…...

地质考察AR远程交互展示系统辅助老师日常授课

广东这片充满活力的土地&#xff0c;孕育了一家引领ARVR科技潮流的杰出企业——深圳华锐视点&#xff0c;作为一家专注于VR/AR技术研究与业务开发的先锋公司。多年来&#xff0c;我们不断突破技术壁垒&#xff0c;将AR增强现实技术与各行各业的实际需求完美结合&#xff0c;助力…...

容器是什么

什么是容器&#xff1f; 容器技术近年来在软件开发和部署中变得越来越重要&#xff0c;尤其是在云计算和微服务架构中。本文将详细介绍什么是容器、其工作原理、优势以及常见的容器技术。 容器的定义 容器是一种轻量级、可移植的虚拟化技术&#xff0c;它允许在一个主机操作…...

一分钟学习数据安全——数字身份的三种模式

微软首席身份架构师金卡梅隆曾说&#xff1a;互联网的构建缺少一个身份层。互联网的构建方式让你无法得知所连接的人和物是什么。这限制了我们对互联网的使用&#xff0c;并让我们面临越来越多的危险。如果我们坐视不管&#xff0c;将面临迅速激增的盗窃和欺诈事件&#xff0c;…...

WPF实现搜索文本高亮

WPF实现搜索文本高亮 1、使用自定义的TextBlock public class HighlightTextblock : TextBlock{public string DefaultText { get; set; }public string HiText{get { return (string)GetValue(HiTextProperty); }set { SetValue(HiTextProperty, value); }}// Using a Depend…...

Vue小程序项目知识积累(三)

1.CSS中的var( ) var() 函数用于插入自定义属性&#xff08;也称为CSS变量&#xff09;的值。 var(--main-bg-color,20rpx) 设置一个CSS变量的值&#xff0c;但是如果 --main-bg-color 变量不存在&#xff0c;它将默认返回 20rpx。 CSS变量必须在一个有效的CSS规则&#xf…...

React Native 之 像素比例(十七)

在 React Native 中&#xff0c;PixelRatio 是一个用于获取设备像素比&#xff08;Pixel Ratio&#xff09;的实用工具。像素比&#xff08;或称为设备像素密度、DPI 密度等&#xff09;是物理像素和设备独立像素&#xff08;DIPs 或 DPs&#xff09;之间的比率。设备独立像素是…...

Leetcode 112:路径总和

给定一个二叉树和一个目标和&#xff0c;判断该树中是否存在根节点到叶子节点的路径&#xff0c;这条路径上所有节点值相加等于目标和。 说明: 叶子节点是指没有子节点的节点。 思路&#xff1a;遍历存储每条路径。当前节点为叶子节点时&#xff0c;求和。并判断是否等于目标…...

电源模块测试系统怎么测试输入电压范围?

在现代电子设备中&#xff0c;电源模块的性能直接影响着整个系统的稳定性和效率。其中&#xff0c;电源输入电压范围是指电源能够接受的输入电压的最小值和最大值&#xff0c;它是确保电源正常工作的重要参数。为了提高测试效率和精度&#xff0c;自动化的测试方法逐渐取代了传…...

实战指南:Vue 2基座 + Vue 3 + Vite + TypeScript微前端架构实现动态菜单与登录共享

实战指南&#xff1a;Vue 2基座 Vue 3 Vite TypeScript子应用vue2微前端架构实现动态菜单与登录共享 导读&#xff1a; 在当今的前端开发中&#xff0c;微前端架构已经成为了一种流行的架构模式。本文将介绍如何结合Vue 2基座、Vue 3子应用、Vite构建工具和TypeScript语言…...

Java面试进阶指南:高级知识点问答精粹(一)

Java 面试问题及答案 1. 什么是Java中的集合框架&#xff1f;它包含哪些主要接口&#xff1f; 答案&#xff1a; Java集合框架是一个设计用来存储和操作大量数据的统一的架构。它提供了一套标准的接口和类&#xff0c;使得我们可以以一种统一的方式来处理数据集合。集合框架主…...

儿童礼物笔记

文章目录 女孩礼物毛绒玩具音乐水晶系列水彩笔 男孩礼物益智类玩具积木类泡沫类机动玩具类 小孩过生日或儿童节&#xff0c;选礼物想破脑袋&#xff0c;做个笔记吧。 如果自家的小孩&#xff0c;还好说些&#xff0c;送亲友就需要动动脑筋。 女孩礼物 毛绒玩具 不错的选择&a…...

LeetCode215数组中第K个最大元素

题目描述 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 解析 快速排序的思想&#xff…...

LeetCode //C - 143. Reorder List

143. Reorder List You are given the head of a singly linked-list. The list can be represented as: L0 → L1 → … → Ln - 1 → Ln Reorder the list to be on the following form: L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … You may not modify the values i…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...