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

详解Jetpack Compose中的状态管理与使用

前言

  引用一段官方描述,如下

由于 Compose 是声明式工具集,因此更新它的唯一方法是通过新参数调用同一可组合项。这些参数是界面状态的表现形式。每当状态更新时,都会发生重组。因此,TextField 不会像在基于 XML 的命令式视图中那样自动更新。可组合项必须明确获知新状态,才能相应地进行更新。

  google想表达的是compose不会像xml布局一样,可以简单的在代码里主动调用方法(比如setText(),setImageResource()等等)就能去刷新UI内容,而是需要通过状态管理通知UI的内容需要更新。 

  而Compose的状态管理更符合MVVM思想的,虽然Jetpack很早之前就已经推出了ViewModel、LiveData、MutableLiveData、DataBinding(这个最有毒,开创了XML写逻辑的先河)作为状态管理。但是因为XML与Activity的定位原因,都让现在的Android编程很难说是MVVM模式,只能说是接近。

  其中尴尬的原因是:

  1.XML既是View层实现编写,但是又无法更新控制View层。并且XML的样式就已经表明它不适合编写逻辑控制View。

  2.Activity既是View层控制器,又不实现View的代码编写。

    他们本应该合二为一,但是却分开了。导致MVC,MVP,MVVM思想都无法完全契合Android平台,使很多新人在Android平台学习使用这3种思想时,会经常陷入困惑。

状态管理涉及到类与方法

  • remember:保存数据,并且在UI更新时会提供保存的值。但是Activity页面退出后会丢失保存的值
  • rememberSaveable:保存数据,并且将值写入到bundle中,然后重新构建Activity的时候,从bundle读数据。这表示Activity退出后也不会丢失值。
  • mutableStateOf :一个可变并且被Compose时刻观察的状态存储,作用就是让Compose可以获知数据已经改变,UI上的内容需要重新绘制。
  • mutableStateListOf:mutableStateOf只能观察单个类型数据的变化,无法观察到集合数据的变化。所以有了mutableStateListOf,方法参数带vararg关键字,所以它也可以是多个List组成的数组
  • mutableStateMapOf:同上,只不过是以哈希的形式,方法参数带vararg关键字,所以它也可以是数组
  • derivedStateOf:定义的对象状态依赖其他的对象状态时,需要使用derivedStateOf,当依赖对象状态发生改变,自己也可以跟着改变。

看完上面的可以明白,remember是用于临时保存数据的,而MutableState是用于通知与传递数据变化的。

remember与mutableStateOf 的使用例子(一个快速了解的Demo)

实现一个按键点击自增数值并且显示的Demo,一般情况下mutableStateOf 与 remember都是配合使用的(但是他们不是绑定关系,都可以单独使用)。直接使用mutableStateOf 与 remember组合使用的区别是什么?请看博客后面的”为什么mutableStateOf不能直接写到方法内部的例子“ 但是,建议你先保留疑问按顺序看下去。

下面代码里展示了3种创建方式,但是这3种方式都是不同的语法糖,结果是一样的。

代码:

class DeploymentActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyButton()}}@Preview(name = "按键自增计数")@Composablefun MyButton() {Column() {/*使用by需要引用import androidx.compose.runtime.getValueimport androidx.compose.runtime.setValue*/var count1 by remember { mutableStateOf(0) }Button(onClick = { count1++ }) {Text(text = "按键A = $count1")}var count2 = remember { mutableStateOf(0) }Button(onClick = { count2.value++ }) {Text(text = "按键B = ${count2.value}")}var (count3, setValue) = remember { mutableStateOf(0) }Button(onClick = { setValue.invoke(count3+1) }) {Text(text = "按键C = $count3")}}}
}

效果动图:

mutableStateListOf的使用例子

mutableStateListOf 是用在集合数据的情况下它能在集合数据变动的情况下触发重组,因为如果使用mutableStateOf将会无法观察到集合数据的变动,从而不触发重组。

private var mImageList = mutableStateListOf<String>()@Composableprivate fun collectContentList() {LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 256.dp),verticalArrangement = Arrangement.spacedBy(20.dp),horizontalArrangement = Arrangement.spacedBy(20.dp),contentPadding = PaddingValues(top = 20.dp, start = 20.dp, end = 20.dp)) {items(mImageList.size) { index ->AsyncImage(model = mImageList[index],contentDescription = null,contentScale = ContentScale.Crop,modifier = Modifier.width(256.dp).height(128.dp).pointerInput(Unit) {detectTapGestures(onTap = {DrawFromActivity.jumpCarryFileImage(context = requireContext(),mImageList[index])},onLongPress = {mCurrentDeleteImagePath = mImageList[index]mIsShowDeleteDialog.value = true})}.clip(RoundedCornerShape(10.dp)))}}}

 

mutableStateMapOf的使用例子

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyMapList()}}@Composablefun MyMapList() {val dataMap = remember {mutableStateMapOf("key1" to "value1","key2" to "value2","key3" to "value3","key4" to "value4")}LazyColumn {items(dataMap.size){ index->val itemKey = dataMap.keys.toMutableList()[index]val itemValue = dataMap[itemKey]itemValue?.let { Text(text = it) }}}}

derivedStateOf的使用例子

 derivedStateOf的使用场景是,某个数据需要依靠其他状态管理的计算或者派生的情况。

代码例子如下:

我们需要计数,并且计数的结果派生一新的需求判断是奇数还是偶数。

    @Preview@Composablefun MyText() {val count = remember { mutableStateOf(0) }//是否是奇数val isOddNumber = remember {derivedStateOf {count.value % 2 != 0}}Text(text = "计数 = ${count.value} 是否是奇数 = ${isOddNumber.value}",color = Color.White,modifier = Modifier.clickable {count.value++})}

结果:

remember的带参使用例子

  remember不带参的使用例子已经在上面说明过了,不在重复举例。现在说说remember的带参使用例子。

  remember的代码块,只会在第一次创建的时候执行一次,后续就不会在执行了。如果我们有需求希望在Compose方法重组的时候remember的代码块在执行一次怎么办? 那就需要使用remember带参的情况,只要改变key就会让remember在compose重组的时候重新执行一次代码块。

举一个反面参考,不带参的代码例子:

    @Composablefun MyText() {//这个count是用来触发整个方法重组的val count = remember { mutableStateOf(0) }//不添加keyval randomNum = remember() {Log.e("zh", "remember被重新执行代码块了")(0..99).random()}Text(text = "按键A = ${count.value}", modifier = Modifier.clickable {count.value++Log.e("zh", "randomNum = ${randomNum}")})}

 点击Text后重组的结果,可以看到随机数没有变化,固定在51,并且在remember代码块里的log日志也没有打印。

带参的例子:

请注意,因为remember是在Compose内部的所以,想让带参remember重新执行代码块就需要让Compose发生一次重组,所以下面的count是用来触发重组的。

    var key = 0@Composablefun MyText() {//这个count是用来触发整个方法重组的val count = remember { mutableStateOf(0) }//添加keyval randomNum = remember(key) {Log.e("zh", "remember被重新执行代码块了")(0..99).random()}Text(text = "按键A = ${count.value}", modifier = Modifier.clickable {key++count.value++Log.e("zh", "key = ${key}")Log.e("zh", "randomNum = ${randomNum}")})}

点击Text后重组的结果,可以因为key的改变,randomNum的remember也被触发重新执行了代码块。从而更新了随机数的值。

rememberSaveable的使用例子

保存数据,并且将值写入到bundle中,然后重新构建Activity的时候,从bundle读数据。这表示Activity退出后也不会丢失值。

 代码:

    @Composablefun MyText() {val count = rememberSaveable {mutableStateOf(0)}Text(text = "计数 = ${count.value}  ",color = Color.Black,modifier = Modifier.clickable {count.value++})}

理解MutableState重组UI组件范围

mutableState的重组UI组件范围是在它读取与写入的范围里的。为了验证这个说法,请看下面的代码例子:

多个@Composable方法组合下的重组UI范围例子1:

下面的代码中,在Column被点击后,增加了count的数值但是并不会引起任何的UI重组。因为三个Text都没有引用count。

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val count = remember { mutableStateOf(1) }Column(modifier = Modifier.clickable { count.value++ }) {Log.e("zh", "Column触发重组")Text1()Text2()Text3()}}}@Composablefun Text1() {Log.e("zh", "Text1触发重组")Text(text = "测试")}@Composablefun Text2() {Log.e("zh", "Text2触发重组")Text(text = "测试")}@Composablefun Text3() {Log.e("zh", "Text3触发重组")Text(text = "测试")}

多个@Composable方法组合下的重组UI范围例子2:

在下面的代码中Text1引用了count数据,所以在点击Columu增加了count数值后,重组范围只在自定义的Text1方法里,在外部的Column也没有触发重组。

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val count = remember { mutableStateOf(1) }Column(modifier = Modifier.clickable { count.value++ }) {Log.e("zh", "Column触发重组")Text1(count)Text2(count)Text3(count)}}}@Composablefun Text1(count: MutableState<Int>) {Log.e("zh", "Text1触发重组 count = ${count.value} count内存地址= ${count}")Text(text = "测试 ${count.value}")}@Composablefun Text2(count: MutableState<Int>) {Log.e("zh", "Text2触发重组")Text(text = "测试")}@Composablefun Text3(count: MutableState<Int>) {Log.e("zh", "Text3触发重组")Text(text = "测试")}

@Composable方法内部的重组范围例子:

 在Text被点击后方法内部的所有组件都被重组了。但是有特例并不是所有情况下整个方法内部都会触发重组,在调用了Button、Surface、CompositionLocalProvider情况下重组范围只会被限制在这些组件的内部(其实Button、Surface内部含CompositionLocalProvider,导致的重组只会限制在他们的范围内)

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyButton()}}@Composablefun MyButton() {val count = remember { mutableStateOf(1) }Log.e("zh", "触发重组1")Column {Log.e("zh", "触发重组2")Column {Log.e("zh", "触发重组3")Text(text = "数值 = ${count.value}", modifier = Modifier.width(100.dp).height(100.dp).clickable { count.value++ })}}}

@Composable方法内部CompositionLocalProvider的重组范围例子:

Button、Surface内部含CompositionLocalProvider,所以一起举例。在下面的代码中,点击任何一个组件增加Count数值后,Column下的任何log都不会触发了,因为重组范围被限定在CompositionLocalProvider。

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyButton()}}@OptIn(ExperimentalMaterialApi::class)@Composablefun MyButton() {val count = remember { mutableStateOf(1) }Log.e("zh", "触发重组1")Column {Log.e("zh", "触发重组2")Column {Log.e("zh", "触发重组3")Button(onClick = { count.value++ }) {Log.e("zh", "Button触发重组")Text(text = "Button = ${count.value}")}CompositionLocalProvider(){Log.e("zh", "CompositionLocalProvider触发重组")Text(text = "CompositionLocalProvider = ${count.value}", modifier = Modifier.width(100.dp).height(100.dp).clickable { count.value++ })}Surface(onClick = { count.value++ },modifier = Modifier.width(100.dp).height(100.dp)) {Log.e("zh", "Surface触发重组")Text(text = "Surface = ${count.value}")}}}}

为什么mutableStateOf不能直接写到方法内部的例子 :

在上面的例子里所有创建mutableStateOf的外部都套了一个remember。 那么肯定有人会疑问,为什么要增加remember? 不直接在方法内部创建mutableStateOf呢? 其实这个问题的关键是理解组件的重组。因为组件方法的每一次重组都会导致 mutableStateOf 被重新创建一次。remember的文字意思是记住,所以remember的作用就是将mutableStateOf或者其他实体数据引用到保存到每个Compose的SlotTable中,不受其重组的影响。

 在下面的代码中,我们故意错误的在组件方法里直接创建mutableStateOf。看看在Text点击后让Count自增后,重组后会引起什么问题:

    @SuppressLint("UnrememberedMutableState") //在内部调用mutableStateOf会出现警告@Composablefun MyButton() {val count = mutableStateOf(1)Log.e("zh", "count地址 = ${count}")Column {//因为Button含有CompositionLocalProvider不会导致外部也触发重组,所以这里用Text替代Text(text = "按键A = ${count.value}", modifier = Modifier.clickable { count.value++ })Log.e("zh", "count = ${count.value}")}}

结果就是每次组件方法的重组也把MutableState重新创建了,导致数值不会自增,并且内存地址每次都是新的。

但是mutableStateOf可以写在外部,下面代码中mCount1是保存在Activity这个类的全局变量中,而count2是保存在Composable创建的Compose的SlotTable中,但是二者在使用上没有什么特别大的区别。

    val mCount1 = mutableStateOf(1)@Composablefun MyText() {val count2 = remember { mutableStateOf(1) }Column {Text(text = "mCount1 ${mCount1}")Text(text = "count2 ${count2}")}}

MutableState通知UI重组机制

这里用下面的图片可以简单了解一下...  .MutableState的机制相当复杂,想要深入了解特别烧脑。因为代码追踪并不好用,你得用到debug调试才能找到他们的观察者消息的发送与接收。个人认为只要了解SnapshotMutableStateImpl,简单的理解State与快照Snapshot的机制即可。

remember的原理

下面用贴源码方式,展示remember的流程,看看remember将数据缓存到哪里去了。

 源码一

 

/*** 记住高阶函数calculation执行后产生的值。重组将总是返回产生的值*/
@Composable
inline fun <T> remember(calculation: @DisallowComposableCalls () -> T): T =currentComposer.cache(false, calculation)

源码二

/*** A Compose compiler plugin API. DO NOT call directly.* 缓存记录,一个组合的组合数据中的值。编译器插件使用它来生成更有效的调用,以便在确定这些操作是安全的时候进行记录。*/
@ComposeCompilerApi
inline fun <T> Composer.cache(invalid: Boolean, block: @DisallowComposableCalls () -> T): T {@Suppress("UNCHECKED_CAST")return rememberedValue().let {if (invalid || it === Composer.Empty) {val value = block()updateRememberedValue(value)value} else it} as T
}

源码三

   override fun updateRememberedValue(value: Any?) = updateValue(value)

源码四

    /*** 将SlotTable的值更新为[value]的当前值。** @param value the value to schedule to be written to the slot table.*/@PublishedApi@OptIn(InternalComposeApi::class)internal fun updateValue(value: Any?) {if (inserting) {//插入新的值writer.update(value)if (value is RememberObserver) {record { _, _, rememberManager -> rememberManager.remembering(value) }abandonSet.add(value)}} else {//更新已经存在的值val groupSlotIndex = reader.groupSlotIndex - 1if (value is RememberObserver) {abandonSet.add(value)}recordSlotTableOperation(forParent = true) { _, slots, rememberManager ->if (value is RememberObserver) {rememberManager.remembering(value)}//这里的set方法可以将新值保存到SlotTable里,并且将旧的值返回when (val previous = slots.set(groupSlotIndex, value)) {is RememberObserver ->//观察者记录管理类,将以前的注册的RememberObserver观察者移除rememberManager.forgetting(previous)//重组范围实施类is RecomposeScopeImpl -> {val composition = previous.compositionif (composition != null) {//释放之前的值previous.release()//设置当前composition失效范围composition.pendingInvalidScopes = true}}}}}}

remember存在的意义是什么

      在文章上面的 “为什么mutableStateOf不能直接写到方法内部的例子” 中已经讲解了大部分。这边在重复啰嗦一下,意义就是给每个Compose保存一份需要缓存的数据,使其不受到Compose重组的影响。这种设计是因为移动平台的应用有切换前后台需求,从而有页面生命周期的概念。需要Compose缓存一份数据用于前后台切换后的数据恢复展示。

相关文章:

详解Jetpack Compose中的状态管理与使用

前言 引用一段官方描述&#xff0c;如下 由于 Compose 是声明式工具集&#xff0c;因此更新它的唯一方法是通过新参数调用同一可组合项。这些参数是界面状态的表现形式。每当状态更新时&#xff0c;都会发生重组。因此&#xff0c;TextField 不会像在基于 XML 的命令式视图中那…...

改进YOLOv7 | 头部解耦 | 将YOLOX解耦头添加到YOLOv7 | 涨点杀器

改进YOLOv7 | 头部解耦 | 将YOLOX解耦头添加到YOLOv7 论文地址:https://arxiv.org/abs/2107.08430 文章目录 改进YOLOv7 | 头部解耦 | 将YOLOX解耦头添加到YOLOv71. 解耦头原理2. 解耦头对收敛速度的影响3. 解耦头对精度的影响4. 代码改进方式第一步第二步第三步第四步第五步参…...

第七章 中断

中断是什么&#xff0c;为什么要有中断 并发是指单位时间内的累积工作量。 并行是指真正同时进行的工作量。 一个CPU在一个时间只能执行一个进程&#xff0c;任何瞬间任务只在一个核心上运行。 而CPU外的设备是独立于CPU的&#xff0c;它与CPU同步运行&#xff0c;CPU抽出一点…...

1116 Come on! Let‘s C(38行代码+详细注释)

分数 20 全屏浏览题目 作者 CHEN, Yue 单位 浙江大学 "Lets C" is a popular and fun programming contest hosted by the College of Computer Science and Technology, Zhejiang University. Since the idea of the contest is for fun, the award rules are f…...

深入学习《c语言函数》

&#x1f4d5;博主介绍&#xff1a;目前大一正在学习c语言&#xff0c;数据结构&#xff0c;计算机网络。 c语言学习&#xff0c;是为了更好的学习其他的编程语言&#xff0c;C语言是母体语言&#xff0c;是人机交互接近底层的桥梁。 本章学习函数。 让我们开启c语言学习之旅吧…...

Pytorch从零开始实现Vision Transformer (from scratch)

Pytorch从零开始实现Vision Transformer 前言一、Vision Transformer架构介绍1. Patch Embedding2. Multi-Head Attention3. Transformer BlockFeed Forward 二、预备知识1. Einsum2. Einops 三、Vision Transformer代码实现0. 导入库1. Patch Embedding2. Residual & Norm…...

ES6函数新增了哪些扩展?

目录 一、参数二、属性函数的length属性name属性 三、作用域四、严格模式五、箭头函数 一、参数 ES6允许为函数的参数设置默认值 function log(x, y World) {console.log(x, y); }console.log(Hello) // Hello World console.log(Hello, China) // Hello China console.log(…...

【firewalld防火墙】

目录 一、firewalld概述二、firewalld 与 iptables 的区别1、firewalld 区域的概念 三、firewalld防火墙默认的9个区域四、Firewalld 网络区域1、区域介绍2、firewalld数据处理流程 五、firewalld防火墙的配置方法1、使用firewall-cmd 命令行工具。2、使用firewall-config 图形…...

CNNs: ZFNet之CNN的可视化网络介绍

CNNs: ZFNet之CNN的可视化网络介绍 导言Deconvnet1. Unpooling2. ReLU3. Transpose conv AlexNet网络修改AlexNet Deconv网络介绍特征可视化 导言 上一个内容&#xff0c;我们主要学习了AlexNet网络的实现、超参数对网络结果的影响以及网络中涉及到一些其他的知识点&#xff0…...

云原生之深入解析Airbnb的动态Kubernetes集群扩缩容

一、前言 Airbnb 基础设施的一个重要作用是保证我们的云能够根据需求上升或下降进行自动扩缩容&#xff0c;我们每天的流量波动都非常大&#xff0c;需要依靠动态扩缩容来保证服务的正常运行。为了支持扩缩容&#xff0c;Airbnb 使用了 Kubernetes 编排系统&#xff0c;并且使…...

Django框架之模板其他补充

本篇文章是对django框架模板内容的一些补充。包含注释、html转义和csrf内容。 目录 注释 单行注释 多行注释 HTML转义 Escape Safe Autoescape CSRF 防止csrf方式 表单中使用 ajax请求添加 注释 单行注释 语法&#xff1a;{# 注释内容 #} 示例&#xff1a; {# 注…...

安装Maven 3.6.1:图文详细教程(适用于Windows系统)

一、官网下载对应版本 推荐使用maven3.6.1版本&#xff0c;对应下载链接&#xff1a; Maven3.6.1下载地址 或者&#xff0c;这里提供csdn下载地址&#xff0c;点击下载即可&#xff1a; Maven3.6.1直链下载 其他版本下载地址&#xff1a; 进入网址&#xff1a;http://mave…...

计算机图形学 | 实验八:Phong模型

计算机图形学 | 实验八&#xff1a;Phong模型 计算机图形学 | 实验八&#xff1a;Phong模型Phong模型光源设置 光照计算定向光点光源聚光 华中科技大学《计算机图形学》课程 MOOC地址&#xff1a;计算机图形学&#xff08;HUST&#xff09; 计算机图形学 | 实验八&#xff1a…...

第三十一回:GestureDetector Widget

文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了ListView响应事件的内容t,本章回中将介绍 GestureDetector Widget.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在这里介绍的GestureDetector是一个事件响应Widget,它可以响应双击事件&#xff0…...

Java面试知识点(全)-Java并发-多线程JUC三- JUC集合/线程池

Java面试知识点(全) 导航&#xff1a; https://nanxiang.blog.csdn.net/article/details/130640392 注&#xff1a;随时更新 JUC集合类 为什么HashTable慢? 它的并发度是什么? 那么ConcurrentHashMap并发度是什么? Hashtable之所以效率低下主要是因为其实现使用了synchro…...

Android 如何获取有效的DeviceId

目录 前言官方唯一标识符建议使用广告 ID使用实例 ID 和 GUID不要使用 MAC 地址标识符特性常见用例和适用的标识符 解决方案DeviceIdANDROID_IDMac地址UUID补充 总结 前言 从 Android 10 开始&#xff0c;应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可…...

<SQL>《SQL命令(含例句)精心整理版(2)》

《SQL命令&#xff08;含例句&#xff09;精心整理版&#xff08;2&#xff09;》 跳转《SQL命令&#xff08;含例句&#xff09;精心整理版&#xff08;1&#xff09;8 函数8.1 文本处理函数8.2 数值处理函数8.3 时间处理函数8.3.1 时间戳转化为自定义格式from_unixtime8.3.2 …...

完全自主研发,聚芯微发布3D dToF图像传感器芯片!

日前&#xff0c;由中国半导体行业协会IC设计分会&#xff08;ICCAD&#xff09;、芯原股份、松山湖管委会主办的主题为“AR/VR/XR元宇宙”的“2023松山湖中国IC创新高峰论坛”正式在广东东莞松山湖召开。武汉市聚芯微电子有限责任公司发布了完全自主知识产权的3D dToF图像传感…...

MySQL 事物(w字)

目录 事物 首先我们来看一个简单的问题 什么是事务 为什么会出现事务 事务的版本支持 事务提交方式 事务常见操作方式 设置隔离级别 事物操作 事物结论 事务隔离级别 理解隔离性 隔离级别 查看与设置隔离性 注意可重复读【Repeatable Read】的可能问题&#xff…...

字节跳动测试岗四面总结....

字节一面 1、 简单做一下自我介绍 2、 简要介绍一下项目/你负责的模块/选一个模块说一下你设计的用例 3 、get请求和post请求的区别 4、 如何判断前后端bug/3xx是什么意思 5、 说一下XXX项目中你做的接口测试/做了多少次 6、 http和https的区别 7、 考了几个ADB命令/查看…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...