繁体   English   中英

Jetpack Compose 将 LiveData 传递给可组合 lambda

[英]Jetpack Compose passing LiveData to a Composable lambda

我无法理解为什么我观察到我的值,因为 state 已正确传递到可组合 lambda 中,但不会触发可组合重构。

这是我的设置。

屏幕

@Composable
fun Screen(
    showBottomSheet: (@Composable () -> Unit) -> Unit,
    viewModel: MyViewModel = hiltViewModel()
) {
    val someValue = viewModel.someValue.observeAsState().value

    MyController(
        onShowBottomSheetClick = {
            showBottomSheet {
                Log.d("DEBUG", "value updated: $someValue")
                BottomSheetLayout(
                    someValue = someValue,
                    onUpdateClick = { newValue -> viewModel.setValue(newValue) }
                )
            }
        }
    )
}

我的控制器

@Composable
fun MyController(
    onShowBottomSheetClick: () -> Unit
) {
    Text(
        text = "show BottomSheet",
        modifier = Modifier.clickable { onShowBottomSheetClick() }
    )
}

底页布局

@Composable
fun BottomSheetLayout(
    someValue: Int,
    onUpdateClick: (Int) -> Unit
) {
    Text(
        text = "Some value: $someValue",
        modifier = Modifier.clickable { onUpdateClick(someValue + 1) }
    )
}

我的视图模型

@HiltViewModel
class MyViewModel @Inject constructor(): ViewModel() {
    private val _someValue: Int? = MutableLiveData(null)
    val someValue: LiveData<Int?> = _someValue

    fun setValue(newValue: Int) {
        _someValue.value = newValue
    }
}

当我运行它并看到 output 时,日志没有显示更新的someValue

value updated: 0
value updated: 0
value updated: 0

但是,如果我将新的 state 值添加到 lambda 本身,它就可以正常工作。

// Screen
// ..
    showBottomSheet {
        val currentValue = viewModel.someValue.observeAsState().value // <-- Note the difference
        Log.d("DEBUG", "value updated: $currentValue")
        BottomSheetLayout(
            someValue = currentValue,
            onUpdateClick = { newValue -> viewModel.setValue(newValue) }
        )
    }
// ..

当我运行它并看到 output 时,日志显示正确更新的值。

value updated: 0
value updated: 1
value updated: 2

为什么会这样? 有什么办法可以将第一个 state 值传递给showBottomSheet可组合 lambda?

先感谢您。

Log.d 是一个副作用,应该与它的一个处理程序一起使用。

阅读有关 Jetpack Compose 副作用的更多信息

使用 LaunchedEffect 或 DisposableEffect

@Composable
fun Screen(
    showBottomSheet: (@Composable () -> Unit) -> Unit,
    viewModel: MyViewModel = hiltViewModel()
) {
    val someValue = viewModel.someValue.observeAsState().value
    
    LaunchedEffect(someValue) {
        Log.d("DEBUG", "value updated: $someValue")
    }

    MyController(
        onShowBottomSheetClick = {
            showBottomSheet {
                BottomSheetLayout(
                    someValue = someValue,
                    onUpdateClick = { newValue -> viewModel.setValue(newValue) }
                )
            }
        }
    )
}

每次您的值更改时都会启动效果

我没有尝试过你的代码,但这看起来像是这个问题中范围重组的效果。 在那个问题中,即使没有记住 mutableState 值也会更新,因为外部 scope 没有重组。 在您的情况下,因为您传递的是 value 而不是 state 因为没有触发重组而没有更新。

为什么没有记忆的 mutableStateOf 有时会起作用?

@Composable
fun Screen(
    showBottomSheet: (@Composable () -> Unit) -> Unit,
    viewModel: MyViewModel = hiltViewModel()
) {
    val someValue = viewModel.someValue.observeAsState().value

    MyController(
        onShowBottomSheetClick = {
            showBottomSheet {
                Log.d("DEBUG", "value updated: $someValue")
                BottomSheetLayout(
                    someValue = someValue,
                    onUpdateClick = { newValue -> viewModel.setValue(newValue) }
                )
            }
        }
    )
}

在此代码中,仅重构了showBottomSheet ,并且由于MyController scope 中没有重构,因此作为值的 someValue 未更新。

使用此代码,我假设showBottomSheet是可组合的,因为您可以调用 @Composable function Flow.collectAsState 您正在重新组合内部的所有内容,这就是为什么它使用viewModel.someValue的最新值重新组合

showBottomSheet {
    val currentValue = viewModel.someValue.observeAsState().value // <-- Note the difference
    Log.d("DEBUG", "value updated: $currentValue")
    BottomSheetLayout(
        someValue = currentValue,
        onUpdateClick = { newValue -> viewModel.setValue(newValue) }
    )
}

使用代理

这将您的值包装到State<T>remember API的方式相同,因此每次您的值更改时都会导致重新组合。

val someValue by viewModel.someValue.observeAsState()

在您的示例中,state 由于.value而立即转换,并且未调用重组。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM