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

安卓jetpack compose学习笔记-状态基础学习

目录

一、MutableState可变状态

二、数据缓存

一)remember

1、介绍

2、代码示例

3、复杂的UI状态和逻辑

二)ViewModel

三)Http请求

三、总结


        在安卓应用中,除了UI之外,另一个关键就是数据的处理。对于Compose UI来说,数据的处理和UI的渲染是天然分开的。比如,使用remember()获取一个MutableState对象,这个数据变化之后,会有机制通知使用这个对象的Compose函数进行更新。

        如果自己创建了一个非MutableState对象,这个对象的改变,不会引发Compose UI的重组,表现在界面就是界面不会有任何反应。可以说,MutableState就是Compose中数据的“双向绑定”。

        如果是不变数据,直接在代码中进行声明即可。如果是可变数据,则必须使用MutableState。

一、MutableState可变状态

        MutableState是Compose中状态管理的基础,当MutableState.value被更新时,MutableState会通知使用过这个对象的Compose组件进行重组,即进行页面刷新。当MutableState.value是自定义对象时,对他更新需要一个对象整个更新,即MutableState.value=newValue不能使用MutableState.value.changeStauts这种改变状态的方法,不然不会通知Compose组件进行重组。

        MutableState通知Compose组件进行数据更新时一种单向流数据,即MutableState数据 => Compose组件。如果Compose组件想要更新MutableState,需要使用事件的方式对MutableState数据进行更新,即MutableState数据 <= Compose组件。

二、数据缓存

        可变数据的分层:

        1、Composition Scope,即组合作用域,也可以理解为Compose函数这一级的作用域。代表功能是remember函数。

        2、Activity/Fragment Scope,可以理解为页面容器这一级的作用域。代表功能是ViewModel。

        3、Application Scope,即应用作用域。可以将数据以文件、数据库、远程存储等方式进行存取,即可实现应用级别的数据作用域,或者也可以采用第三方框架。

一)remember

1、介绍

        remember是缓存机制。当Compose组件进行重组时会重新执行代码,所以MutableState需要被包含在remember()函数中,remember()可以保证Compose的多次重组中,使用的对象是同一个MutableState,而不是每次重组都重新创建一遍MutableState对象。

        remember缓存的状态可以跨重组存在,但是不能跨Activity或者跨进程存在。可以把remember创建的对象提到上级的Compose,进而在多个Compose中引用同一个缓存对象。

2、代码示例

        代码示例:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview@Composable
fun RememberCompose() {Column(verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally,modifier = Modifier.fillMaxSize()) {var mutableState = remember { mutableStateOf("A") }Text(text = mutableState.value)Button(onClick = {mutableState.value = "A"}) {Text("设置为A")}Button(onClick = {mutableState.value = "B"}) {Text("设置为B")}}
}@Preview
@Composable
fun PreRememberCompose() {RememberCompose()
}

        效果:

        备注:rememberSavable缓存的状态可以跨Activity或者跨进程存在,当手动退出应用时,缓存数据才会被清空。实现原理就是把数据以Bundle的形势进行保存。类似这类API就不详细介绍了,可以根据需求在网络上寻找对应的API。

3、复杂的UI状态和逻辑

        在Compose中定义一个remember对象的方式,适合少量UI状态,简单的UI逻辑。

        对于一些较为复杂的UI状态和逻辑,可以使用一个类将相关状态整合到一起,这个叫StateHolder。这种方式需要注意要对MutableState.value进行赋值更新,否则会无法更新Compose UI。

二)ViewModel

        viewModel()会从ViewModelStore中获取实例,如果没有实例,就创建一个并存入ViewModelStore。ViewModelStore可能是Activity或者Fragment。

        定义ViewModel的方式就是定义一个类,然后继承ViewModel。然后可以用viewModel()函数获取这个类的实例。

        代码:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModelclass CounterViewModel : ViewModel() {private val _counter = mutableStateOf(0)val counter: State<Int> = _counterfun increment() {_counter.value = _counter.value + 1}fun decrement() {if (_counter.value > 1) {_counter.value = _counter.value - 1}}
}@Composable
fun CounterScreen() {var viewModel: CounterViewModel = viewModel()CounterComponent(viewModel.counter,viewModel::increment,viewModel::decrement)
}@Composable
fun CounterComponent(x0: State<Int>, x1: () -> Unit, x2: () -> Unit) {Column(verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally,modifier = Modifier.fillMaxSize()) {Text(text = "value: ${x0.value}")Button(onClick = x1) {Text("increment")}Button(onClick = x2) {Text("decrement")}}
}@Preview
@Composable
fun PreCounterScreen() {CounterScreen()
}

        效果:

三)Http请求

        首先定义Http的普通类定义:

import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.get
import io.ktor.client.request.headers
import io.ktor.client.statement.bodyAsText
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.json.Jsonsuspend fun main() {println(Http.visit("http://www.bai1du.com"))
}object Http {suspend fun visit(url: String): String {var httpClient = HttpClient(CIO) {install(ContentNegotiation) {json(Json {prettyPrint = trueisLenient = true})}engine {requestTimeout = 15000}}var errorMessage = ""try {var response = httpClient.get(url) {headers {append("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")}}if (response.status.value == 200) {val content = response.bodyAsText()println("百度首页内容长度: ${content.length}")var take = content.take(100)println("前100个字符: $take")return take} else {println("请求失败,状态码: ${response.status}")errorMessage += "请求失败,状态码: ${response.status}\n"}} catch (e: Exception) {println("visit $url error!")errorMessage += "message: ${e.message}\n"errorMessage += "toString: ${e.toString()}\n"e.printStackTrace()} finally {httpClient.close()}return "http get error!\n$errorMessage"}
}

        然后定义ViewModel:

import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launchclass UrlViewModel : ViewModel() {private val _urlData = mutableStateOf(UrlData())val urlData: State<UrlData> = _urlDatadata class UrlData(var url: String = "http://www.baidu.com",var content: String = "")fun fetchData() {viewModelScope.launch {var url = _urlData.value.url_urlData.value = UrlData(url,Http.visit(url))}}fun updateUrl(url: String){_urlData.value = UrlData(url,"")}fun clearContent() {var url = _urlData.value.url_urlData.value = UrlData(url,"")}
}

        最后编写UI代码:

import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.viewmodel.compose.viewModel
import cn.yy.httptest.ui.theme.HttpTestTheme@SuppressLint("StateFlowValueCalledInComposition")
@Composable
private fun AppCompose() {var viewModel: UrlViewModel = viewModel()UrlView(viewModel.urlData,viewModel::updateUrl,viewModel::fetchData,viewModel::clearContent)
}@Composable
fun UrlView(urlData: State<UrlViewModel.UrlData>,updateUrl: (String) -> Unit,fetchData: () -> Unit,clearContent: () -> Unit
) {Column(verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally,modifier = Modifier.fillMaxSize()) {Text(text = "url: ${urlData.value.url}")TextField(value = urlData.value.url,onValueChange = updateUrl)Button(onClick = {fetchData()}) {Text("访问")}Button(onClick = {clearContent()}) {Text("clear content")}Text(text = "content: ${urlData.value.content}")}
}@Preview(showBackground = true)
@Composable
fun AppComposePreview() {HttpTestTheme {AppCompose()}
}

        效果:

        这里是通过ViewModel的方式获取http网站数据,也可以用这种方式获取文件数据等。

三、总结

        Compose UI的数据管理有两个关键点:

        1、MutableState状态的保存及更新。

        2、remember、ViewModel等方式的不同范围的缓存机制。

        

        

        

http://www.lqws.cn/news/482815.html

相关文章:

  • 【代码解析】opencv 安卓 SDK sample - 1 - HDR image
  • Dify安装与使用
  • 《情感反诈模拟器》2025学习版
  • 【redis使用场景——缓存——双写一致性】
  • 算法 : 把数字翻译成字符串
  • react day.js使用及经典场景
  • 掌握C++核心特性
  • UI TARS 和 Magentic-UI的区别和差异
  • Java面试复习指南:基础、多线程、JVM、Spring、算法精要
  • 飞轮储能VSG控制策略辅助双馈风机一次调频的仿真模型研究
  • RL 基础 (CH3,动态规划)
  • Dify 1.4.3技术研究报告:新一代AI应用开发平台的核心优势与行业实践
  • 【PyTorch项目实战】CycleGAN:无需成对训练样本,支持跨领域图像风格迁移
  • 稳压二极管“漏电流”的动态电阻效应
  • 【编程语言】javascript、java、go对比应用场景
  • 9大策略深度解析MySQL多表JOIN性能优化
  • BERT 模型准备与转换详细操作流程
  • Bytemd@Bytemd/react详解(编辑器实现基础AST、插件、跨框架)
  • Macbook M4芯片 MUMU模拟器安装使用burpsuit抓包教程APP
  • WEB3合约开发以太坊中货币单位科普
  • 应急推进器和辅助推进器诊断函数封装
  • 媒体AI关键技术研究
  • linux----------------进程VS线程
  • 零基础学习Redis(14) -- Spring中使用Redis
  • RA4M2开发IOT(9)----动态显示MEMS数据
  • 深入理解Spring MVC:构建灵活Web应用的基石
  • 【SQL语法汇总】
  • Python 商务数据分析—— NumPy 学习笔记Ⅰ
  • 由浅入深详解前缀树-Trie树
  • 数智管理学(二十四)