[Android]Jetpack Compose状态管理

在 Jetpack Compose 中,状态管理是构建交互式应用程序的核心。Compose 设计思想强调了不变性和重新组合的概念,以支持高效的 UI 更新。

一、使用 Remember 和 MutableState 管理状态

remember 和 mutableStateOf 是管理状态的基础工具,特别适用于维护 UI 组件的响应式状态。这里,我们将通过几个示例详细介绍如何使用这些工具进行状态管理。

1. 基本计数器示例

我们从最简单的计数器示例开始,展示如何使用 remember 和 mutableStateOf 来存储和更新一个计数值。

import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

@Composable
fun SimpleCounter() {
    // 使用 remember 和 mutableStateOf 来记住状态
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("点击了 $count 次")
    }
}

2. 列表项选中示例

在下一个示例中,我们将演示如何管理一个列表中每个项目的选中状态。

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.selection.selectable
import androidx.compose.material.Text
import androidx.compose.runtime.*

@Composable
fun SelectableItemList(items: List<String>) {
    // 使用 remember 创建一个状态列表,初始值为 false,表示未选中
    val selectedStates = remember { items.map { mutableStateOf(false) } }

    Column {
        items.forEachIndexed { index, item ->
            val isSelected = selectedStates[index]

            Text(
                text = item,
                modifier = Modifier.selectable(
                    selected = isSelected.value,
                    onClick = { isSelected.value = !isSelected.value }
                )
            )
        }
    }
}

3. 用户输入表单示例

此示例展示如何处理用户输入,使用 mutableStateOf 来响应用户的实时输入。

import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

@Composable
fun UserInputForm() {
    // 记住用户输入的文本状态
    var userInput by remember { mutableStateOf("") }

    BasicTextField(
        value = userInput,
        onValueChange = { userInput = it },
        decorationBox = { innerTextField ->
            if (userInput.isEmpty()) {
                Text("请输入内容")
            }
            innerTextField()
        }
    )
}

4. 动态样式切换示例

最后一个示例是动态切换组件样式,用户可以通过点击按钮来改变文本的颜色。

import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color

@Composable
fun DynamicStyleExample() {
    // 记住文本颜色的状态
    var color by remember { mutableStateOf(Color.Black) }

    Button(onClick = { color = if (color == Color.Black) Color.Red else Color.Black }) {
        Text("点击改变颜色", color = color)
    }
}

5.MutableState 与 ViewModel 结合使用

ViewModel 可以直接持有由 mutableStateOf 创建的状态。由于 mutableStateOf 是线程安全的,它可以在 ViewModel 中安全使用,并且能够保证状态的更新能够正确地通知到所有观察者(即 Composable 函数)。

在 Jetpack Compose 中,remember 用于在组件的重组过程中保持状态。然而,在 ViewModel 中使用 mutableStateOf 不需要 remember,原因归结于两点:

  • ViewModel 的生命周期:ViewModel 的生命周期通常比单个 Composable 函数要长。当屏幕旋转或配置更改时,组件可能会被销毁并重新创建,但 ViewModel 会保留,保持其状态。这是 ViewModel 设计的一部分,旨在存储和管理 UI 相关数据,以便在诸如配置更改之类的事件中,数据可以持续存在。

  • 状态的持久化:当你在 ViewModel 中使用 mutableStateOf 时,状态绑定到 ViewModel 的生命周期。你不需要使用 remember 来防止状态在 Composable 重组时丢失,因为 ViewModel 已经为你处理了状态的持久化。remember 在 Composable 函数内部使用,用于管理那些需要在重组过程中保留的状态。但是,由于 ViewModel 的状态已经是稳定的(即不依赖于特定的 Composable 实例),因此无需在 ViewModel 中使用 remember

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel

class MyViewModel : ViewModel() {
    // 使用 mutableStateOf 来持有状态
    var count by mutableStateOf(0)
        private set  // 限制外部对状态的修改,只能通过 ViewModel 内部方法修改

    fun incrementCount() {
        count++
    }
}

@Composable
fun CounterScreen(viewModel: MyViewModel = viewModel()) {
    // 直接观察 ViewModel 中的 mutableStateOf 状态
    Column {
        Text(text = "Count: ${viewModel.count}")
        Button(onClick = { viewModel.incrementCount() }) {
            Text("Increment")
        }
    }
}

二、使用 LiveData 管理状态

在 Jetpack Compose 中使用 LiveData 进行状态管理。通过 observeAsState() 方法,LiveData 可以被转换为 Compose 可用的状态,使得原有基于 LiveData 的架构可以与 Compose 无缝集成。这不仅有助于迁移现有的 Android 应用程序,还保持了数据的一致性和响应性。

1.LiveData 与 ViewModel 结合使用

虽然 LiveData 可以独立使用,但通常推荐与 ViewModel 一起使用,原因包括:

  • 生命周期感知:ViewModel 与 LiveData 都是生命周期感知的。当 LiveData 与 ViewModel 结合使用时,它们可以确保数据在配置更改(如屏幕旋转)后仍然保持一致,并且不会导致内存泄漏或不必要的数据重新加载。

  • 数据封装:ViewModel 可以作为 UI 控制器和数据层之间的桥梁,封装业务逻辑和数据访问。LiveData 则用于观察数据变化,使得 UI 可以根据数据的变化自动更新。

  • 资源管理:ViewModel 管理的 LiveData 可以利用 ViewModel 的生命周期,自动处理观察者的注册和注销,简化资源管理。当 ViewModel 被清除时,它可以自动清理其内部的 LiveData 观察者,优化资源使用。

(1).计数器示例

首先,我们创建一个简单的 ViewModel,它持有一个 LiveData,用于跟踪计数器的值。

import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData

class CounterViewModel : ViewModel() {
    // 初始化 LiveData
    val count = MutableLiveData(0)

    fun increment() {
        // 更新 LiveData 的值
        count.value = (count.value ?: 0) + 1
    }
}


@Composable
fun CounterScreen(viewModel: CounterViewModel = viewModel()) {
    // 将 LiveData 转换为 Compose 可用的状态
    val count = viewModel.count.observeAsState(0)

    Button(onClick = { viewModel.increment() }) {
        Text("点击了 ${count.value} 次")
    }
}

(2).列表数据示例

在这个示例中,我们将使用 LiveData 来管理一个列表数据,并在 Compose UI 中显示这些数据。

import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData

class ListViewModel : ViewModel() {
    // 使用 LiveData 管理列表数据
    val items = MutableLiveData(listOf("苹果", "香蕉", "橘子"))
}

@Composable
fun ListScreen(viewModel: ListViewModel = viewModel()) {
    // 观察 LiveData 中的列表数据
    val items = viewModel.items.observeAsState(listOf())

    LazyColumn {
        items(items.value) { item ->
            Text(text = item)
        }
    }
}

(3).数据加载状态示例

这个示例演示如何使用 LiveData 管理数据加载的状态。

import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.*

class DataViewModel : ViewModel() {
    val data = MutableLiveData<String>()
    val loading = MutableLiveData(false)

    fun loadData() {
        loading.value = true
        viewModelScope.launch {
            delay(2000) // 模拟网络请求
            data.value = "加载完成的数据"
            loading.value = false
        }
    }
}

@Composable
fun DataScreen(viewModel: DataViewModel = viewModel()) {
    val data = viewModel.data.observeAsState("")
    val loading = viewModel.loading.observeAsState(false)

    Column {
        if (loading.value) {
            Text("正在加载...")
        } else {
            Text("数据:${data.value}")
            Button(onClick = { viewModel.loadData() }) {
                Text("加载数据")
            }
        }
    }
}

2.LiveData 独立使用

LiveData 是一个观察者模式的实现,可以用来在数据源和观察者(通常是 UI 组件)之间建立一个可观察的数据连接。理论上,您可以在任何地方使用 LiveData 来传递数据,不一定非要在 ViewModel 中。

例如,您可以在普通的类中使用 LiveData 来管理数据变化:

class DataRepository {
    private val _data = MutableLiveData<String>()
    val data: LiveData<String> = _data

    fun loadData() {
        // 模拟数据加载
        _data.value = "新数据"
    }
}

然后,在 Compose 或其他观察者中观察这些数据:

@Composable
fun DataDisplay(repository: DataRepository) {
    val data = repository.data.observeAsState("初始数据")
    Text(text = data.value)
}

三、使用 StateFlow 管理状态

使用 StateFlow 管理状态,并在 Compose UI 中通过 collectAsState() 收集这些状态,实现了响应式 UI 更新。

1.StateFlow 与 ViewModel 结合使用

StateFlow在使用 Jetpack Compose 的应用中,它经常与 ViewModel 一起使用,这主要是因为以下几个原因:

  • 生命周期感知:ViewModel 负责处理与 UI 相关的数据和逻辑,同时具有感知生命周期的能力。这意味着 ViewModel 可以在配置更改(如屏幕旋转)和其他生命周期事件中持久保存其状态,防止数据丢失。

  • 内存管理:ViewModel 在适当的生命周期结束时可以进行清理,防止内存泄漏。使用 ViewModel 提供了一个自然的地方来存放和管理 StateFlow,并确保在 ViewModel 清理时取消相关的协程。

  • 模块化和解耦:通过在 ViewModel 中封装状态管理逻辑,可以使 UI 组件(Composables)保持轻量和专注于呈现,从而更容易测试和维护。

(1).简单计数器示例

首先,创建一个 ViewModel,里面使用 StateFlow 来管理计数器的状态:

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class CounterViewModel : ViewModel() {
    // 私有的 MutableStateFlow,用于内部修改值
    private val _count = MutableStateFlow(0)
    // 公共的 StateFlow,外部只能读取
    val count: StateFlow<Int> = _count

    // 函数用于增加计数
    fun increment() {
        _count.value += 1
    }
}

@Composable
fun CounterScreen(viewModel: CounterViewModel = viewModel()) {
    // 使用 collectAsState 在 Compose 中观察 StateFlow 的值
    val count = viewModel.count.collectAsState()
    
    Button(onClick = { viewModel.increment() }) {
        Text("点击了 ${count.value} 次")
    }
}

(2).用户列表示例

现在,我们来创建一个更复杂的例子,比如管理一个用户列表:

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

data class User(val name: String, val age: Int)

class UserViewModel : ViewModel() {
    private val _users = MutableStateFlow<List<User>>(emptyList())
    val users: StateFlow<List<User>> = _users

    fun addUser(user: User) {
        _users.value = _users.value + user
    }
}

@Composable
fun UserListScreen(viewModel: UserViewModel = viewModel()) {
    val users = viewModel.users.collectAsState()

    LazyColumn {
        items(users.value) { user ->
            Text(text = "姓名:${user.name}, 年龄:${user.age}")
        }
    }
    Button(onClick = { viewModel.addUser(User("新用户", 30)) }) {
        Text("添加用户")
    }
}

(3).加载状态和数据示例

在很多应用中,我们需要表示加载状态和数据。我们可以使用 StateFlow 来实现这一点:

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class DataViewModel : ViewModel() {
    private val _data = MutableStateFlow("加载中...")
    val data: StateFlow<String> = _data

    init {
        loadData()
    }

    private fun loadData() = viewModelScope.launch {
        // 模拟网络请求延迟
        kotlinx.coroutines.delay(2000)
        _data.value = "数据加载完成"
    }
}

@Composable
fun DataLoaderScreen(viewModel: DataViewModel = viewModel()) {
    val data = viewModel.data.collectAsState()

    Text("数据状态:${data.value}")
}

2.StateFlow 独立使用

StateFlow 本身是一个非常通用的响应式编程工具,它可以在 Kotlin 的任何部分使用,不仅限于与 ViewModel 结合。例如,你可以在以下场景中使用 StateFlow

  • 在服务中管理状态:如果你的应用有一个后台服务需要维护和更新状态,可以使用 StateFlow 来实现状态的发布和订阅。

  • 在仓库层(Repository)管理状态:在架构中,仓库层负责数据的逻辑和存储。使用 StateFlow 可以在仓库层发布数据更新,然后由 ViewModel 订阅这些更新,进一步简化数据流。

  • 在单例模式或其他组件中:在需要跨多个组件或屏幕共享状态的情况下,可以使用单例模式或其他结构来持久化 StateFlow

例如,如果你想在一个单例类中使用 StateFlow 来管理某些全局配置,可以这样做:

object Configuration {
    private val _darkModeEnabled = MutableStateFlow(false)
    val darkModeEnabled: StateFlow<Boolean> = _darkModeEnabled

    fun toggleDarkMode() {
        _darkModeEnabled.value = !_darkModeEnabled.value
    }
}

@Composable
fun SettingsScreen() {
    val darkModeEnabled = Configuration.darkModeEnabled.collectAsState()
    Switch(
        checked = darkModeEnabled.value,
        onCheckedChange = { Configuration.toggleDarkMode() }
    )
}

四、使用状态提升(State Hoisting)管理状态

状态提升是一种将状态管理逻辑从子组件提升到其父组件的技术,一般结合事件回调使用,这样可以使子组件更加可复用、独立和易于测试。

状态提升的核心概念是:在 Composable 函数中,不直接创建和维护状态,而是通过参数从父组件接收状态和事件处理函数。这样做的好处是:

  • 可复用性:组件不再依赖于特定的状态实现,可以在不同的环境中重用。
  • 清晰的数据流:状态在组件树中向下流动,事件向上冒泡,使得数据流向清晰可追踪。
  • 更易于测试:由于状态被提升,测试时可以直接操作状态而不必触发特定的 UI 交互。

1.简单计数器示例

首先,我们从一个简单的计数器开始,演示没有使用状态提升的版本,然后将其重构为使用状态提升。

未使用状态提升的版本

import androidx.compose.runtime.*
import androidx.compose.material.Button
import androidx.compose.material.Text

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("点击了 $count 次")
    }
}

使用状态提升的版本


@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }
    EnhancedCounter(count = count, onIncrement = { count++ })
}

@Composable
fun EnhancedCounter(count: Int, onIncrement: () -> Unit) {
    Button(onClick = onIncrement) {
        Text("点击了 $count 次")
    }
}

2.用户输入表单示例

此示例展示如何对一个简单的文本输入进行状态提升。

未使用状态提升的版本

import androidx.compose.runtime.*
import androidx.compose.material.TextField

@Composable
fun UserInput() {
    var text by remember { mutableStateOf("") }

    TextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("输入内容") }
    )
}

使用状态提升的版本

@Composable
fun UserInputScreen() {
    var text by remember { mutableStateOf("") }
    EnhancedUserInput(text = text, onTextChange = { text = it })
}

@Composable
fun EnhancedUserInput(text: String, onTextChange: (String) -> Unit) {
    TextField(
        value = text,
        onValueChange = onTextChange,
        label = { Text("输入内容") }
    )
}

3.开关控制示例

在这个示例中,我们将创建一个开关控制,并使用状态提升来管理其状态。

未使用状态提升的版本

import androidx.compose.runtime.*
import androidx.compose.material.Switch

@Composable
fun ToggleSwitch() {
    var isChecked by remember { mutableStateOf(false) }

    Switch(
        checked = isChecked,
        onCheckedChange = { isChecked = it }
    )
}

使用状态提升的版本

@Composable
fun ToggleScreen() {
    var isChecked by remember { mutableStateOf(false) }
    EnhancedToggleSwitch(isChecked = isChecked, onCheckedChange = { isChecked = it })
}

@Composable
fun EnhancedToggleSwitch(isChecked: Boolean, onCheckedChange: (Boolean) -> Unit) {
    Switch(
        checked = isChecked,
        onCheckedChange = onCheckedChange
    )
}

五、使用 CompositionLocal 管理状态

使用CompositionLocal隐式传值:https://blog.csdn.net/wsyx768/article/details/138066319

在 Jetpack Compose 中,CompositionLocal 提供了一种在组件树中传递数据的方法,而无需通过参数显式传递。这对于在多个层级的组件之间共享数据非常有用,使得状态管理更加灵活和集中。

1.定义和使用 CompositionLocal

要使用 CompositionLocal,你需要首先定义它,然后在组件树的某个层级提供一个值,之后就可以在任何子组件中访问这个值。

(1).定义一个 CompositionLocal

compositionLocalOf 用于创建一个 CompositionLocal,它需要一个默认值。这意味着当在组件树的任何位置访问这个 CompositionLocal 的值时,如果没有明确的提供者(CompositionLocalProvider),它将回退到这个默认值。

staticCompositionLocalOf 创建的 CompositionLocal 不需要默认值。如果你尝试在没有提供者的情况下访问它的值,则会抛出异常。这强制开发者必须在使用这些数据之前明确地提供它们,增加了类型安全性。

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.staticCompositionLocalOf

// 使用默认值
val LocalUserInfo = compositionLocalOf { "默认用户" }

// 没有默认值,使用时需要确保提供
val LocalEnvironment = staticCompositionLocalOf<String>()

(2).在组件树中提供值

使用 CompositionLocalProvider 在组件树中提供 CompositionLocal 的值。

@Composable
fun App() {
    CompositionLocalProvider(LocalUserInfo provides "Alice") {
        UserProfile()
    }
}

(3).访问值

在任何子组件中,你可以使用 LocalUserInfo.current 来访问当前的值。

@Composable
fun UserProfile() {
    val userInfo = LocalUserInfo.current
    Text(text = "当前用户: $userInfo")
}

2.示例

(1).主题颜色管理示例

这个示例展示了如何使用 CompositionLocal 来管理和访问应用的主题颜色。

定义一个主题颜色的 CompositionLocal

import androidx.compose.ui.graphics.Color
import androidx.compose.runtime.staticCompositionLocalOf

val LocalAppColor = staticCompositionLocalOf { Color.Green }

提供颜色值

@Composable
fun MyApp() {
    CompositionLocalProvider(LocalAppColor provides Color.Blue) {
        MyScreen()
    }
}

使用颜色值

@Composable
fun MyScreen() {
    val color = LocalAppColor.current
    Text(text = "欢迎来到我的应用!", color = color)
}

(2).多语言支持示例

这个示例演示如何使用 CompositionLocal 来支持多语言。

定义一个多语言相关的 CompositionLocal

val LocalResources = staticCompositionLocalOf { "默认文本" }

提供资源

@Composable
fun MultiLanguageApp() {
    CompositionLocalProvider(LocalResources provides "Hola Mundo!") {
        Greeting()
    }
}

使用资源

@Composable
fun Greeting() {
    val greetingText = LocalResources.current
    Text(text = greetingText)
}

六、使用副作用(Side Effects)处理器管理状态

在 Jetpack Compose 中,处理副作用(Side Effects)是一种管理和响应可观察状态变化的方法。Compose 提供了一系列效果处理器,帮助开发者在合适的生命周期时机执行代码,这些工具对于状态管理和与外部系统(如数据库和网络服务)的交互非常重要。

使用 Jetpack Compose 的副作用处理器可以有效地管理异步操作、资源清理、事件监听和状态派生。这些处理器帮助开发者在正确的生命周期时机执行特定的代码,从而提高应用的性能和响应性。

通过以下示例,我们可以看到不同类型的副作用处理器如何在实际应用中被利用来进行状态管理和事件处理。

1.LaunchedEffect

LaunchedEffect 用于在组件首次进入组合或其键值改变时启动一个协程。这对于执行只需发生一次的异步任务,如数据加载,非常有用。

示例:加载数据

@Composable
fun LoadDataExample() {
    val data = remember { mutableStateOf("") }

    // 当组件首次加载或 key 值变化时,重新加载数据
    LaunchedEffect(Unit) {
        data.value = fetchDataFromNetwork()
    }

    Text("加载的数据: ${data.value}")
}

suspend fun fetchDataFromNetwork(): String {
    // 模拟网络请求
    delay(1000)  // 假设请求需要1秒完成
    return "从网络获取的数据"
}

2.rememberCoroutineScope

rememberCoroutineScope 用于在 Composable 函数内部获取一个与组件生命周期绑定的协程作用域,使得可以在用户交互或其他事件触发时启动协程。

示例:用户交互触发数据加载

@Composable
fun InteractiveDataLoading() {
    val scope = rememberCoroutineScope()
    val data = remember { mutableStateOf("") }

    Button(onClick = {
        scope.launch {
            data.value = fetchDataFromNetwork()
        }
    }) {
        Text("点击加载数据")
    }

    if (data.value.isNotEmpty()) {
        Text("加载的数据: ${data.value}")
    }
}

3.DisposableEffect

DisposableEffect 用于管理需要清理的资源,如订阅和取消订阅事件。在 Composable 函数退出组合或键值改变时,它会自动执行清理代码。

示例:事件监听与清理

@Composable
fun EventListenerExample() {
    val lifecycleOwner = LocalLifecycleOwner.current

    DisposableEffect(lifecycleOwner) {
        val listener = LifecycleEventObserver { _, event ->
            println("生命周期事件: $event")
        }
        lifecycleOwner.lifecycle.addObserver(listener)

        // 当 Composable 退出组合或 lifecycleOwner 改变时调用
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(listener)
        }
    }

    Text("监听生命周期事件中...")
}

4.derivedStateOf

derivedStateOf 用于创建一个依赖于其他状态的派生状态。只有当依赖的状态改变时,派生状态才会更新,这有助于优化性能。

示例:计算派生状态

@Composable
fun DerivedStateExample() {
    val count = remember { mutableStateOf(0) }
    val isEven = derivedStateOf { count.value % 2 == 0 }

    Button(onClick = { count.value++ }) {
        Text("增加计数")
    }

    Text("计数 ${count.value} 是偶数吗? ${if (isEven.value) "是" else "否"}")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/582239.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【kettle006】kettle访问华为openGauss高斯数据库并处理数据至execl文件

1.一直以来想写下基于kettle的系列文章&#xff0c;作为较火的数据ETL工具&#xff0c;也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下华为openGauss高斯数据库相关知识体系 3.欢迎批评指正&#xff0c;跪谢…

10.通用定时器

驱动电机 RGB LED亮度&#xff08;呼吸灯&#xff09; 舵机&#xff08;遥控车、机械臂&#xff09; 通用定时器作用 1.延时 2.定时器更新中断 3.输出比较&#xff08;PWM波、驱动IO输出波形&#xff08;脉冲&#xff09;&#xff09; 4.输入捕获&…

C语言——小知识和小细节17

一、未能给指针成功赋值 #include <stdio.h> #include <stdlib.h> #include <string.h>void GetMemory(char* p) {p (char*)malloc(20 * sizeof(char)); }void Test() {char* str NULL;GetMemory(str);strcpy(str, "Hello World!");printf(&quo…

分布式ID之雪花算法

1. Seata对雪花算法生成ID的改良 滑动验证页面 &#xff08;含代码&讲解&#xff09; Seata基于改良版雪花算法的分布式UUID生成器分析&#xff1a;时间戳和节点ID位置进行了调换。官网&#xff1a;Seata基于改良版雪花算法的分布式UUID生成器分析 | Apache Seata关于新版…

【平台开发】MTK6833 实现lk下CQE接口移植 - cmdq irq

1.cmdq_irq 检测中断bit 2.目前遇到问题 任务执行后&#xff0c;没有触发对应中断&#xff0c;伴有错误发生&#xff0c;但任务完成标志位能检测到 寄存器CQIS,CQDQS等均为0&#xff0c;CQTCN为任务完成寄存器看到置1&#xff0c;CQTERRI检测到8000错误 错误详情如下&#xf…

MATLAB : interp1()用法介绍

目录 一、基本语法&#xff1a; 二、实例&#xff1a; 1.样条拟合减振器阻尼曲线 ​2.PP拟合时间温度曲线 interp1 是 MATLAB 中的一个函数&#xff0c;用于在一维数据上执行插值操作。这个函数可以帮助你估计或计算已知数据点之间未知点的值。以下是 interp1 函数的基本用…

计算机网络复习和重点

一、计算机网络概述 网络发展历史、网络的定义、分类和组成、 网络协议分层模型介绍&#xff08;OSI和TCP/IP模型的比较&#xff09; 重点&#xff1a;网络协议的概念、分层 分层的目的&#xff1a;降低复杂性分层的好处和坏处&#xff1a;好处是设计简答&#xff0c;坏处是…

免费分享一套微信小程序扫码点餐(订餐)系统(uni-app+SpringBoot后端+Vue管理端技术实现) ,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序扫码点餐(订餐)系统(uni-appSpringBoot后端Vue管理端技术实现) &#xff0c;分享下哈。 项目视频演示 【免费】微信小程序扫码点餐(订餐)系统(uni-appSpringBoot后端Vue管理端技术实现) Java毕…

基于数据湖的企业中台解决方案

什么是数据湖? 数据湖是一个以原始格式(通常是对象块或文件)存储数据的系统或存储库。数据湖通常是所有企业数据的单一存储。用于报告、可视化、高级分析和机器学习等任务。数据湖可以包括来自关系数据库的结构化数据(行和列)、半结构化数据(CSV、日志、XML、JSON)、非结构化…

封装umi-request时通过 AbortController 配置取消请求

一、关键部分 一、在封装的request.ts中 声明一个 abortControllers 对象用于存储要取消的请求&#xff08;我用了-s表示复数&#xff0c;多个abortcontroller对象&#xff0c;与下面&#x1f447;的单个abortController区分&#xff09;封装取消请求的函数cancelRequest, 传入…

Rust Web开发实战:打造高效稳定的服务端应用

Rust Web开发实战&#xff1a;打造高效稳定的服务端应用 本书将带领您从零开始构建Web应用程序&#xff0c;无论是API、微服务还是单体应用&#xff0c;都将一一涵盖。您将学到如何优雅地对外开放API&#xff0c;如何连接数据库以安全存储数据&#xff0c;以及如何对应用程序进…

Mysql基础(三)DDL之create table语句

一 create table 创表 说明&#xff1a; create table相关语句从功能上进行讲解补充&#xff1a; 前面已经讲解过相关的约束,已进行相关的铺垫声明&#xff1a; 参考价值较少,了解即可 ① 基本语法 思考&#xff1a; 约束加在哪里? ② 创建新表 强调&#xff1a;使…

RCD吸收电路:开关电源高频干扰的有效消除器

开关电源中除了我们常规介绍的差模噪声源和共模噪声源&#xff0c;还存在一些其它的噪声源也应该解决&#xff0c;这些高频噪声源同样会带来电磁兼容问题&#xff0c;因此我们需要关注。这里介绍两种干扰源&#xff0c;一种是MOS管的通断带来的高频振荡噪声&#xff0c;另一种是…

Eclipse C++ 无法debug 问题

环境&#xff1a; ubuntu20.04 Eclipse CDT&#xff08;x86_64) 工程&#xff0c;使用的是默认的CMake Project 现象&#xff1a; 1. 使用Eclipse&#xff0c; 加了断点后&#xff0c;debug 无法停在断点&#xff1b;step over 执行后是从main 直接执行到exit &#xff…

ubuntu24.04 正式放弃VNC

1、ubuntu22.04支持情况 去年9月在22.04中测试发现由于gnome启用Wayland桌面&#xff0c;然而Wayland和vnc兼容不佳&#xff0c;就已经黑屏等问题&#xff0c;当时是vnc和ms-rd(微软远程桌面)两个菜单。 Ubuntu22.04 vnc远程黑屏_ubuntu 远程桌面vnc黑屏-CSDN博客文章浏览阅读…

鸿蒙开发HarmonyOS4.0入门与实践

鸿蒙开发HarmonyOS4.0 配合视频一起食用&#xff0c;效果更佳 课程地址&#xff1a;https://www.bilibili.com/video/BV1Sa4y1Z7B1/ 源码地址&#xff1a;https://gitee.com/szxio/harmonyOS4 准备工作 官网地址 鸿蒙开发者官网&#xff1a;https://developer.huawei.com/con…

u盘量产工具拥有分区功能,它把一个U盘分成数个移动盘,更改U盘介质类型(Fixed 和 Removabe),供大家学习研究参考~

非常受欢迎的u盘量产工具。最新版拥有分区功能&#xff0c;它把一个U盘分成数个移动盘&#xff0c;更改U盘介质类型(Fixed 和 Removabel)。数码之家量产工具官方版不是数据恢复&#xff0c;是对U盘底层硬件信息的恢复(非硬件损坏)&#xff0c;使因为底层硬件信息受损电脑无法识…

【stm32】swjtu西南交大嵌入式实验三 外部中断实验:按键中断

项目源文件&#xff1a;https://download.csdn.net/download/qq_61814350/89222788?spm1001.2014.3001.5501 实验内容&#xff1a; 1、编写程序&#xff0c;设置主程序&#xff1a;跑马灯以 0.2s 的速度旋转&#xff1b;将 KB1 设置为外部中断&#xff0c;下 降沿触发&…

在ubuntu 24.04 上安装vmware workstation 17.5.1

ubuntu安装在新组装的i9 14900机器上&#xff0c;用来学习笨叔的ARM64体系结构编程&#xff0c;也熟悉Linux的用法。但有时候写文档总是不方便&#xff0c;还是需要window来用。因此想在ubuntu 24.04上安装Linux版本的vmware worksation 17.5.1以虚拟机的方式安装windows 11。其…

【软测学习笔记】测试入门Day03

&#x1f31f;博主主页&#xff1a;我是一只海绵派大星 &#x1f4da;专栏分类&#xff1a;软件测试笔记 &#x1f4da;参考教程&#xff1a;黑马教程❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、缺陷 1、定义 2、缺陷标准 3、缺陷产生的原因 4、缺陷的生命周…