我一直在使用 Jetpack Compose Desktop。我注意到一些我真的不明白的事情:
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
@Composable
@Preview
fun App() {
var text by mutableStateOf("Hello, World!")
MaterialTheme {
TextField(text, onValueChange = { text = it })
Button(onClick = {
text = "Hello, Desktop!"
}) {
Text(text)
}
}
}
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
App()
}
}
Run Code Online (Sandbox Code Playgroud)
为什么我可以更改 中的文本TextField?我认为在每次重组时,可变状态都会使用初始值重新实例化:所以Text应该无法更改
import androidx.compose.desktop.ui.tooling.preview.Preview
import …Run Code Online (Sandbox Code Playgroud) 下面的两个示例简单地将“a”添加到给定的默认值。该compose_version使用的1.0.0-alpha03是最新的截至今天(据我所知)。
这个例子与我在研究过程中发现的大多数例子最相似。
示例 1
@Composable
fun MyScreen() {
val (name, setName) = remember { mutableStateOf("Ma") }
Column {
Text(text = name) // 'Ma'
Button(onClick = {
setName(name + "a") // change it to 'Maa'
}) {
Text(text = "Add an 'a'")
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,这并不总是实用的。例如,数据比单个字段更复杂。例如一个类,甚至一个Room data class.
示例 2
// the class to be modified
class MyThing(var name: String = "Ma");
@Composable
fun MyScreen() {
val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) }
Column …Run Code Online (Sandbox Code Playgroud) android state kotlin android-jetpack android-jetpack-compose
考虑下面的片段
fun doSomething(){
}
@Composable
fun A() {
Column() {
val counter = remember { mutableStateOf(0) }
B {
doSomething()
}
Button(onClick = { counter.value += 1 }) {
Text("Click me 2")
}
Text(text = "count: ${counter.value}")
}
}
@Composable
fun B(onClick: () -> Unit) {
Button(onClick = onClick) {
Text("click me")
}
}
Run Code Online (Sandbox Code Playgroud)
现在,当按下“click me 2”按钮时,B compose 函数将被重新组合,尽管其中的任何内容都没有改变。
澄清: doSomething 用于演示目的。如果您坚持要一个实际的例子,您可以考虑以下 B 的用法:
B{
coroutinScope.launch{
bottomSheetState.collapse()
doSomething()
}
}
Run Code Online (Sandbox Code Playgroud)
从 compose 编译器报告中我可以看到 B …
我用来TextField获取用户输入并使用 stateflow 来处理视图模型中的文本状态/值。
问题是每次TextField的值发生变化时,HomeContent()函数都会被重新组合。
布局检查器输出图像
我的问题是,仅仅HomeContent()因为值发生变化就可以重构整个函数TextField,还是有办法避免函数重构?
视图模型
class MyViewModel() : ViewModel() {
private val _nameFlow = MutableStateFlow("")
val nameFlow = _nameFlow.asStateFlow()
fun updateName(name: String) {
_nameFlow.value = name
}
}
Run Code Online (Sandbox Code Playgroud)
主要活动
class MainActivity : ComponentActivity() {
private val myViewModel by viewModels<MyViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppArchitectureTheme {
HelloScreen(myViewModel)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
主屏幕
@Composable
fun HelloScreen(viewModel: MyViewModel) {
val name = viewModel.nameFlow.collectAsState()
HelloContent(
provideName = { …Run Code Online (Sandbox Code Playgroud) 我知道Column(){...}当b1orb2改变时,将会重新组合。
如果我希望只有改变的Column(){...}时候才可以重新组合,而改变的 时候不重新组合,怎么办?b2Column(){...}b1
@Composable
fun ScreenDetail(
mViewMode: SoundViewModel
) {
val b1=mViewMode.a1.collectAsState(initial = 0)
val b2=mViewMode.a2.collectAsState(initial = 0)
Column() {
Text(" ${b1.value} ${b2.value}")
Text(Calendar.getInstance().time.toSeconds())
}
}
fun Date.toSeconds():String{
return SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US).format(this)
}
class SoundViewModel(): ViewModel() {
var i = 0
val a1: Flow<Int> = flow {
while (true) {
emit(i++)
delay(1000)
}
}
val a2: Flow<Int> = flow {
while (true) {
emit(i)
delay(2000)
}
}
}
Run Code Online (Sandbox Code Playgroud) 我创建了一个仅显示一个图标、两个文本和两个按钮的应用程序。单击任何按钮时,相应的文本都会更新,因为它取决于我的函数中传递的值。但与文本一起,每次图标重新组合时,它甚至不依赖于任何值。
data class TestUIState(
val counterA: Int = 0,
val counterB: Int = 0,
)
@HiltViewModel
class TestViewModel @Inject constructor() : ViewModel() {
val uiFlow = MutableStateFlow(TestUIState())
val data: TestUIState
get() = uiFlow.value
fun increaseCounterA() {
uiFlow.value = data.copy(counterA = data.counterA + 1)
}
fun increaseCounterB() {
uiFlow.value = data.copy(counterB = data.counterB + 1)
}
}
@Composable
fun TestCompose(
uiValueState: State<TestUIState>,
increaseCounterA: () -> Unit,
increaseCounterB: () -> Unit,
) {
Column(modifier = Modifier.fillMaxSize()) {
Icon(
painter = painterResource(id = …Run Code Online (Sandbox Code Playgroud)