《Jetpack Compose从入门到实战》第九章 Accompanist 与第三方组件库

目录
- Accompanist
- SystemUiController
- Pager
- SwipeRefresh
- Flow Layout
- Insets
- Lottie
- Coil
- AsyncImage
- SubcomposeAsyncImage
- AsyncImagePainter
Accompanist
- 最新可用版本
- accompanist官方文档
SystemUiController
- 依赖:implementation “com.google.accompanist:accompanist-systemuicontroller:<version>”
@Composable
fun SystemUiTest() {Box(modifier = Modifier.fillMaxSize()) {val systemUiController = rememberSystemUiController()val useDarkIcons = MaterialTheme.colors.isLightSideEffect {systemUiController.setSystemBarsColor(color = Color.Transparent, darkIcons = useDarkIcons)}
// TopAppBar(title = { Text(text = "TopAppBar") }, modifier = Modifier.statusBarsPadding(), backgroundColor = Color.Gray)//使用com.google.accompanist:accompanist-insets-ui:0.30.1 实现沉浸式状态栏的效果TopAppBar(title = { Text(text = "TopAppBar") }, backgroundColor = Color.Gray, contentPadding = WindowInsets.statusBars.asPaddingValues())}
}
@Composable
fun SystemUiControllerDemo() {val systemUiController = rememberSystemUiController()val useDarkIcons = MaterialTheme.colors.isLightval colorPanel = listOf(Color.Gray,Color.Red,Color.Black,Color.Cyan,Color.Transparent,Color.DarkGray,Color.LightGray,Color.Yellow)SideEffect {systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)}Column(Modifier.systemBarsPadding().fillMaxSize().background(Color(0xFF0079D3))) {colorPanel.forEach {Box(modifier = Modifier.fillMaxWidth().height(48.dp).background(it).clickable {systemUiController.setSystemBarsColor(it, useDarkIcons)})}}
}
- 略直接设置状态栏和底部导航栏颜色的方法
Pager
- implementation “com.google.accompanist:accompanist-pager:$accompanist_version”
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PagerTest() {Box(modifier = Modifier.fillMaxSize()) {val pagerState = rememberPagerState()val scope = rememberCoroutineScope()HorizontalPager(pageCount = 3, modifier = Modifier.fillMaxSize(), state = pagerState) { page ->when (page) {0 -> ColorBox(color = Color.Blue, pageIndex = page)1 -> ColorBox(color = Color.Cyan, pageIndex = page)2 -> ColorBox(color = Color.Magenta, pageIndex = page)}}SideEffect {scope.launch {delay(3000)pagerState.scrollToPage(2)}}}
}@Composable
fun ColorBox(color: Color, pageIndex: Int) {Box(modifier = Modifier.fillMaxSize().background(color = color), contentAlignment = Alignment.Center) {Text(text = "page $pageIndex")}
}
- 略直接跳转到某个页面的方法
@OptIn(ExperimentalPagerApi::class)
@Composable
fun PagerDemo() {val pagerState = rememberPagerState()val scope = rememberCoroutineScope()var selectedScreens by remember { mutableStateOf(0) }val screens = listOf(Screens("首页", Icons.Filled.Home) { Home() },Screens("我喜欢的", Icons.Filled.Favorite) { Favorite() },Screens("设置", Icons.Filled.Settings) { Settings() })Scaffold(bottomBar = {BottomNavigationBar(selectedScreens,screens,onClick = {selectedScreens = itscope.launch { pagerState.scrollToPage(selectedScreens) }})}) {HorizontalPager(count = screens.size,modifier = Modifier.fillMaxSize(),state = pagerState) { page ->screens.forEachIndexed { index, screens ->when (page) {index -> screens.content()}}}}LaunchedEffect(pagerState) {snapshotFlow { pagerState.currentPage }.collect { page ->selectedScreens = page}}}@Composable
fun Home() {Box(modifier = Modifier.fillMaxSize().background(Color.Gray),contentAlignment = Alignment.Center) {Text(text = "1. 首页🤭",style = MaterialTheme.typography.h5)}
}@Composable
fun Favorite() {Box(modifier = Modifier.fillMaxSize().background(Color(0xFFF8F8F8)),contentAlignment = Alignment.Center) {Text(text = "2. 我喜欢的❤",style = MaterialTheme.typography.h5)}
}
@Composable
fun Settings() {Box(modifier = Modifier.fillMaxSize(),contentAlignment = Alignment.Center) {Text(text = "3. 设置⚙",style = MaterialTheme.typography.h5)}
}
@Composable
fun BottomNavigationBar(selectedScreen: Int,screens: List<Screens>,onClick: (targetIndex: Int) -> Unit
) {NavigationBar {screens.forEachIndexed { index, screen ->NavigationBarItem(icon = { Icon(screen.iconVector, contentDescription = null) },label = { Text(screen.label) },selected = selectedScreen == index,onClick = { onClick(index) })}}
}data class Screens(val label: String,val iconVector: ImageVector,val content: @Composable () -> Unit
)
SwipeRefresh
- implementation “com.google.accompanist:accompanist-swiperefresh:$accompanist_version”
@Preview
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SwipeRefreshTest() {Box(modifier = Modifier.fillMaxSize()) {val viewModel: MyViewModel = viewModel()val isRefreshing by viewModel.isRefreshing.collectAsState()val background by animateColorAsState(targetValue = viewModel.background, animationSpec = tween(1000), label = "backgroundAnim")/* SwipeRefresh(state = rememberSwipeRefreshState(isRefreshing), onRefresh = { viewModel.refresh() }) {Box(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).background(background))}*/val pullRefreshState = rememberPullRefreshState(refreshing = isRefreshing, onRefresh = { viewModel.refresh() })Box(modifier = Modifier.fillMaxSize().pullRefresh(pullRefreshState).verticalScroll(rememberScrollState()).background(background),) {PullRefreshIndicator(isRefreshing, pullRefreshState, modifier = Modifier.align(Alignment.TopCenter))}}
}class MyViewModel : ViewModel() {private val _isRefreshing = MutableStateFlow(false)private val colorPanel = listOf(Color.Gray, Color.Red, Color.Black, Color.Cyan, Color.DarkGray, Color.LightGray, Color.Yellow)val isRefreshing: StateFlow<Boolean>get() = _isRefreshingvar background by mutableStateOf(Color.Gray)fun refresh() {viewModelScope.launch {_isRefreshing.emit(true)delay(1000)background = colorPanel.random()_isRefreshing.emit(false)}}}
Flow Layout
- 会自动换行的row和Column
- implementation “com.google.accompanist:accompanist-flowlayout:$accompanist_version”
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun FlowLayoutTest() {Column(modifier = Modifier.fillMaxSize()) {FlowRow(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically, maxItemsInEachRow = 3) {Text(text = "text1")Text(text = "text2")Text(text = "text3")Text(text = "text4")Text(text = "text5")Text(text = "text6")}Divider(modifier = Modifier.fillMaxWidth())FlowColumn(modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.SpaceEvenly, horizontalAlignment = Alignment.CenterHorizontally, maxItemsInEachColumn = 3) {Text(text = "text1")Text(text = "text2")Text(text = "text3")Text(text = "text4")Text(text = "text5")Text(text = "text6")}}
}
@Composable
fun Tag(modifier: Modifier = Modifier,shape: Shape = CircleShape,elevation: Dp = 0.dp,leadingIcon: @Composable (() -> Unit)? = null,trailingIcon: @Composable (() -> Unit)? = null,text: String,textStyle: TextStyle = TextStyle(fontWeight = FontWeight.Normal,fontSize = 16.sp,letterSpacing = 0.15.sp),backgroundColor: Color = Color(0xFFE8E8E8),border: BorderStroke? = null,onClick:() -> Unit
){Surface(shape = shape,color = backgroundColor,modifier = modifier,elevation = elevation,border = border) {Row(modifier = Modifier.clickable(onClick = onClick).padding(start = 15.dp, end = 15.dp, top = 8.dp, bottom = 8.dp),verticalAlignment = Alignment.CenterVertically,) {when{leadingIcon != null -> {CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high,content = leadingIcon)Spacer(Modifier.padding(horizontal = 4.dp))Text(text = text,style = textStyle,)}trailingIcon != null -> {Text(text = text,style = textStyle,)Spacer(Modifier.padding(horizontal = 4.dp))CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high,content = trailingIcon)}else -> {Text(text = text,style = textStyle,)}}}}
}@Composable
fun FlowLayoutDemo() {Surface(modifier = Modifier.systemBarsPadding().fillMaxWidth(),elevation = 8.dp) {FlowRow(modifier = Modifier.padding(8.dp),crossAxisSpacing = 12.dp,mainAxisSpacing = 10.dp) {Tag(leadingIcon = {Icon(painterResource(id = R.drawable.wechat), null, tint = Color.White)},text = "WeChat",elevation = 6.dp,textStyle = TextStyle(Color.White),backgroundColor = Color(0xFF07C160)) { }Tag(leadingIcon = {Icon(painterResource(id = R.drawable.twitter), null, tint = Color.White)},text = "Twitter",elevation = 6.dp,textStyle = TextStyle(Color.White),backgroundColor = Color(0xFF1DA1F2)) { }Tag(leadingIcon = {Icon(painterResource(id = R.drawable.github), null, tint = Color.White)},text = "Github",elevation = 6.dp,textStyle = TextStyle(Color.White),backgroundColor = Color(0xFF181717)) { }Tag(leadingIcon = {Icon(painterResource(id = R.drawable.microsoftedge), null, tint = Color(0xFF0078D7))},text = "Edge",elevation = 6.dp) { }Tag(leadingIcon = {Icon(painterResource(id = R.drawable.microsoft), null, tint = Color(0xFF5E5E5E))},text = "Microsoft",elevation = 6.dp) { }}}
}
Insets
- implementation “com.google.accompanist:accompanis-inss-ui:<version>”
@Composable
fun InsetsDemo() {val systemUiController = rememberSystemUiController()val useDarkIcons = MaterialTheme.colors.isLightSideEffect {systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)}Scaffold(topBar = {TopAppBar(title = {Text("TopAppBar")},backgroundColor = Color.Gray,contentPadding = WindowInsets.statusBars.asPaddingValues())},modifier = Modifier.fillMaxSize(),contentColor = Color.Black) { }
}
Lottie
- 添加依赖配置 implementation “com.airbnb.android:lottie-compose:$lottieVersion”
- 创建Lottie动画
- 创建两个状态用来描述动画的速度和开始暂停状态
var isPlaying by remember {mutableStateOf(true)}var speed by remember {mutableStateOf(1f)}
- 加载Lottie动画资源,这里用本地加载方式
- Lottie框架提供了加载res/raw,加载URL,加载手机目录下的静态资源,加载asset目录下的静态资源,加载json字符串的功能
val lottieComposition by rememberLottieComposition(spec = RawRes(R.raw.lottie),)
- 接下来创建Lottie动画状态
val lottieAnimationState by animateLottieCompositionAsState (composition = lottieComposition,iterations = LottieConstants.IterateForever,isPlaying = isPlaying,speed = speed,restartOnPlay = false)
- 最后设置动画资源句柄和动画状态
LottieAnimation(lottieComposition,lottieAnimationState,modifier = Modifier.size(400.dp))
Coil
- 添加依赖: implementation “io.coil-kt:coil-compose:$coil_version”
AsyncImage
@Preview
@Composable
fun AsyncImageDemo() {AsyncImage(model = ImageRequest.Builder(LocalContext.current).data(ImageUrl).crossfade(true).build(),//model = (ImageUrl),contentDescription = stringResource(R.string.description),placeholder = painterResource(id = R.drawable.place_holder),error = painterResource(id = R.drawable.error),onSuccess = {Log.d(TAG, "success")},onError = { error ->Log.d(TAG, "error")},onLoading = { loading ->Log.d(TAG, "loading")},modifier = Modifier.clip(CircleShape))
}
SubcomposeAsyncImage
@Preview
@Composable
fun SubcomposeAsyncImageDemo() {SubcomposeAsyncImage(model = "ImageUrl",loading = { CircularProgressIndicator() },contentDescription = "compose_museum")
}
@Preview
@Composable
fun SubcomposeAsyncImageDemo() {SubcomposeAsyncImage(model = "ImageUrl",contentDescription = "compose_museum") {if (painter.state is AsyncImagePainter.State.Loading || painter.state is AsyncImagePainter.State.Error) {CircularProgressIndicator()} else {SubcomposeAsyncImageContent()}}
}
SubcomposeAsyncImage(model = ImageRequest.Builder(LocalContext.current).data(ImageUrl.testUrl1).size(1920,1080),.build(),contentDescription = null,) {val state = painter.statewhen(state) {is AsyncImagePainter.State.Loading -> CircularProgressIndicator()is AsyncImagePainter.State.Error -> Text("${state.result.throwable}")is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent()is AsyncImagePainter.State.Empty -> Text("Empty")}}
AsyncImagePainter
- 这个组件是底层API,使用时会出现很多不可预期的行为,所以建议用前面两个
- 如果项目要求不能用AsyncImage则用这个
- 不能用Success状态来判断,否则图片不能加载成功
val painter = rememberAsyncImagePainter(model = ImageRequest.Builder(LocalContext.current).data("https://pic-go-bed.oss-cn-beijing.aliyuncs.com/img/20220316151929.png").build()
)
if (painter.state is AsyncImagePainter.State.Loading) {CircularProgressIndicator()
}
Image(painter = painter,contentDescription = stringResource(R.string.description)
)
《Jetpack Compose从入门到实战》第一章 全新的 Android UI 框架
《Jetpack Compose从入门到实战》 第二章 了解常用UI组件
《Jetpack Compose从入门到实战》第三章 定制 UI 视图
《Jetpack Compose从入门到实战》第八章 Compose页面 导航
《Jetpack Compose从入门到实战》第九章 Accompanist 与第三方组件库
相关文章:
《Jetpack Compose从入门到实战》第九章 Accompanist 与第三方组件库
目录 AccompanistSystemUiControllerPagerSwipeRefreshFlow LayoutInsets LottieCoilAsyncImageSubcomposeAsyncImageAsyncImagePainter Accompanist 最新可用版本accompanist官方文档 SystemUiController 依赖:implementation “com.google.accompanist:accompa…...
Centos7 docker 容器内root身份应用自启动 /usr/sbin/init 问题
Centos7 docker 容器内root身份应用自启动 & /usr/sbin/init 问题 环境:我在一个 docker 容器内手动安装了 mysql、nginx、autotestsystem(自己的服务); mysql 和 nginx 都做了服务脚本:mysqld.service、nginx.se…...
STL学习笔记之容器
首先我们要学习的是容器 第一个是容器的初始化(构造方式)有三种方式 分别是 第一种 int arr[]{1,2,3} vector<int> v1(arr,arr3) 即容器存放的种类和从另外一个数组去拷贝一段数据。 第二种 vector<int> v2(3,10); 第一个3是指存放…...
Java基础---第十二篇
系列文章目录 文章目录 系列文章目录一、获取一个类Class对象的方式有哪些?二、ArrayList 和 LinkedList 的区别有哪些?三、用过 ArrayList 吗?说一下它有什么特点?一、获取一个类Class对象的方式有哪些? 搞清楚类对象和实例对象,但都是对象。 第一种:通过类对象的 get…...
Acwing 841. 字符串哈希
Acwing 841. 字符串哈希 题目描述思路讲解代码展示 题目描述 思路讲解 代码展示 #include <iostream> #include <algorithm>using namespace std;typedef unsigned long long ULL;const int N 100010, P 131; // P 131 或者13331(经验值)int n, m; char str[N]…...
NEON优化:性能优化经验总结
NEON优化:性能优化经验总结 1. 什么是 NEONArm Adv SIMD 历史 2. 寄存器3. NEON 命名方式4. 优化技巧5. 优化 NEON 代码(Armv7-A内容,但区别不大)5.1 优化 NEON 汇编代码5.1.1 Cortex-A 处理器之间的 NEON 管道差异5.1.2 内存访问优化 Reference: NEON优…...
C++ 并发编程实战 第九章
目录 9.1 线程池 9.1.1 最简易可行的线程池 9.1.2 等待提交给线程池的任务完成运行 9.1.3等待其他任务完成的任务 9.1.4 避免任务队列上的争夺 9.1.5 任务窃取 9.2 中断线程 9.2.1 发起一个线程,以及把他中断 9.2.2 检测线程是否被中断 9.2.3 中断条件变…...
【Java】super 关键字用法
目录 this与super区别 1.访问成员变量-示例代码 继承中构造方法的访问特点 2.访问构造方法-示例代码: 继承中成员方法访问特点 3.访问成员方法-示例代码: super 关键字的用法和 this 关键字相似 this : 代表本类对象的引用super : 代表父类存储空间…...
前端笔试题总结,带答案和解析
1. 执行以下程序,输出结果为() var x 10; var y 20; var z x < y ? x:y; console.log(xx;yy;zz);A x11;y21;z11 B x11;y20;z10 C x11;y21;z10 D x11;y20;z11 初始化x的值为10,y的值为20,x < y返回结果为tru…...
Omniverse Machinima
Omniverse Machinima App | NVIDIA Omniverse Machinima 是 NVIDIA 推出的一款实时动画创作工具,可用于在虚拟世界中制作和操纵角色及其环境。该工具使用 Universal Scene Description (USD) 作为其通用场景描述格式,可与多种 3D 建模、动画和渲染应用程…...
【测试人生】游戏业务测试落地精准测试专项的一些思路
精准测试在互联网领域有广泛的应用。以变更为出发点,通过对变更内容进行分析,可以确定单次变更具体涉及到哪些模块和功能点,以及是否存在夹带风险,从而从QA的视角,可以知道哪些功能模块需要做测试,以及哪些…...
Redis 数据类型底层原理
String 内部编码有三种:int、embstr、raw int:如果一个字符串对象保存的是整数值,并且这个整数值可以用 long类型来表示(不超过 long 的表示范围,如果超过了 long 的表示范围,那么按照存储字符串的编码来存储…...
EasyEdge 智能边缘控制台通过sdk发布应用
离线部署SDK生成 模型部署完成后会出现下载SDK的按钮,点击按钮下载SDK并保存好SDK。 进入EasyDL官网的技术文档 安装智能边缘控制台 跟着教程,完成安装:点此链接 树莓派4b是Linux arm64的架构,点击对应的链接进行下载。 下载完成…...
centos软件设置开机启动的方式
以下以redis作为案例: 开机启动方式一 [Unit] Descriptionredis-server Afternetwork.target [Service] Typeforking # 这里需要修改自己的配置文件 ExecStart/usr/local/bin/redis-server /etc/redis/redis.conf PrivateTmptrue [Install] WantedBymulti-user.tar…...
二叉树和堆
二叉树不存在度大于2的结点(每个根最多只有两个子结点)二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树 两个特殊的二叉树——(满二叉树,完全二叉树) 满二叉树——每个根结点都有左右…...
洛谷P5732 【深基5.习7】杨辉三角题解
目录 题目【深基5.习7】杨辉三角题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1传送门 代码解释亲测 题目 【深基5.习7】杨辉三角 题目描述 给出 n ( n ≤ 20 ) n(n\le20) n(n≤20),输出杨辉三角的前 n n n 行。 如果你不知道什么是杨辉三角…...
Docker 精简安装 Nacos 2.2.1 单机版本
准备工作: 1)已安装docker 2)数据库准备,演示使用MySql5.7版本 1、拉取 [rootTseng-HW ~]# docker pull nacos/nacos-server:v2.2.1 v2.2.1: Pulling from nacos/nacos-server 2d473b07cdd5: Already exists 77c5a601c050: Pul…...
IntelliJ IDEA配置Cplex12.6.3详细步骤
Cplex12.6.3版IntelliJ IDEA配置详细步骤 一、Cplex12.6.3版下载地址二、Cplex安装步骤三、IDEA配置CPLEX3.1 添加CPLEX安装目录的cplex.jar包到项目文件中3.2 将CPLEX的x64_win64文件夹添加到IDEA的VM options中 四、检查IDEA中Cplex是否安装成功卸载Cplex 一、Cplex12.6.3版下…...
2023 年最佳多 GPU 深度学习系统指南
动动发财的小手,点个赞吧! 本文[1]提供了有关如何构建用于深度学习的多 GPU 系统的指南,并希望为您节省一些研究时间和实验时间。 1. GPU 让我们从有趣(且昂贵)的部分开始! 购买 GPU 时的主要考虑因素是&am…...
Kotlin异常处理runCatching,getOrNull,onFailure,onSuccess(1)
Kotlin异常处理runCatching,getOrNull,onFailure,onSuccess(1) fun main(args: Array<String>) {var s1 runCatching {1 / 1}.getOrNull()println(s1) //s11,打印1println("-")var s2 ru…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...
【Redis】Redis从入门到实战:全面指南
Redis从入门到实战:全面指南 一、Redis简介 Redis(Remote Dictionary Server)是一个开源的、基于内存的键值存储系统,它可以用作数据库、缓存和消息代理。由Salvatore Sanfilippo于2009年开发,因其高性能、丰富的数据结构和广泛的语言支持而广受欢迎。 Redis核心特点:…...
