Jetpack Compose State Hoisting, Previews, and ViewModels best practices(Jetpack组合状态吊装、预览和视图模型最佳实践)
问题描述
因此,Jetpack Compose中推荐的事情似乎是将状态从您的组合中提升出来,使它们成为无状态、可重用和可测试的,并允许在预览中轻松使用它们。 所以不是像
这样的东西@Composable
fun MyInputField() {
var text by remember { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it })
}
您可以像这样提升状态
@Composable
fun MyInputField(text: String, onTextChange: (String) -> Unit) {
TextField(value = text, onValueChange = onTextChange)
}
这很好,但是一些更复杂的用法怎么办? 让我们假设我有一个由可组合的表示的屏幕,在View和ViewModel之间有多个交互。此屏幕拆分为多个内部可组合内容(例如,一个用于标题,一个用于正文,而正文又被拆分为多个较小的可组合内容)
- 您不能在Composable中创建ViewModel(至少使用
viewModel()
可以手动实例化),并在Preview
中使用此Composable(预览不支持这样创建ViewModel) - 在内部组合中使用ViewModel会使它们成为有状态的,不是吗?
因此,我看到的解决方案是仅在最高可组合级别实例化我的视图模型,然后仅将表示状态的val
传递给子可组合对象,并回调ViewModel函数。
但这太疯狂了,我不会通过单独的参数将我所有的ViewModel状态和函数传递给所有需要它们的可组合对象。
例如,将它们分组到data class
中可能是一种解决方案
data class UiState(
val textInput: String,
val numberPicked: Int,
……
并可能为回调创建另一个回调? 但这仍然是在创建一个全新的类,只是为了模拟视图模型已有的东西。
我实际上看不到最好的方法是什么,而且我在任何地方都找不到任何关于这方面的东西
推荐答案
管理复杂状态的好方法是将所需的复杂行为封装到类中,并使用记住函数,同时尽可能多地使用无状态小工具,并在需要时随时更改状态的任何属性。
SearchTextField
是一个只使用状态提升的组件,SearchBar
有向后箭头和SearchTextField
,本身也是一个无状态的可组合组件。这两者与搜索栏的父级之间的通信仅通过回调函数来处理,这使得SearchTextField都是可重用的,并且很容易在预览中使用默认状态进行预览。HomeScreen
包含此状态以及您管理更改的位置。
完全实施是posted here。
@Composable
fun <R, S> rememberSearchState(
query: TextFieldValue = TextFieldValue(""),
focused: Boolean = false,
searching: Boolean = false,
suggestions: List<S> = emptyList(),
searchResults: List<R> = emptyList()
): SearchState<R, S> {
return remember {
SearchState(
query = query,
focused = focused,
searching = searching,
suggestions = suggestions,
searchResults = searchResults
)
}
}
记住函数以保留仅在合成期间评估的状态。
class SearchState<R, S>(
query: TextFieldValue,
focused: Boolean,
searching: Boolean,
suggestions: List<S>,
searchResults: List<R>
) {
var query by mutableStateOf(query)
var focused by mutableStateOf(focused)
var searching by mutableStateOf(searching)
var suggestions by mutableStateOf(suggestions)
var searchResults by mutableStateOf(searchResults)
val searchDisplay: SearchDisplay
get() = when {
!focused && query.text.isEmpty() -> SearchDisplay.InitialResults
focused && query.text.isEmpty() -> SearchDisplay.Suggestions
searchResults.isEmpty() -> SearchDisplay.NoResults
else -> SearchDisplay.Results
}
}
并通过将状态传递给其他可组合或按ViewModel作为
来更改UI的任何部分中的状态fun HomeScreen(
modifier: Modifier = Modifier,
viewModel: HomeViewModel,
navigateToTutorial: (String) -> Unit,
state: SearchState<TutorialSectionModel, SuggestionModel> = rememberSearchState()
) {
Column(
modifier = modifier.fillMaxSize()
) {
SearchBar(
query = state.query,
onQueryChange = { state.query = it },
onSearchFocusChange = { state.focused = it },
onClearQuery = { state.query = TextFieldValue("") },
onBack = { state.query = TextFieldValue("") },
searching = state.searching,
focused = state.focused,
modifier = modifier
)
LaunchedEffect(state.query.text) {
state.searching = true
delay(100)
state.searchResults = viewModel.getTutorials(state.query.text)
state.searching = false
}
when (state.searchDisplay) {
SearchDisplay.InitialResults -> {
}
SearchDisplay.NoResults -> {
}
SearchDisplay.Suggestions -> {
}
SearchDisplay.Results -> {
}
}
}
}
这篇关于Jetpack组合状态吊装、预览和视图模型最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:Jetpack组合状态吊装、预览和视图模型最佳实践


- MalformedJsonException:在第1行第1列路径中使用JsonReader.setLenient(True)接受格式错误的JSON 2022-01-01
- 如何检查发送到 Android 应用程序的 Firebase 消息的传递状态? 2022-01-01
- Android - 拆分 Drawable 2022-01-01
- 在测试浓缩咖啡时,Android设备不会在屏幕上启动活动 2022-01-01
- 使用自定义动画时在 iOS9 上忽略 edgesForExtendedLayout 2022-01-01
- android 4中的android RadioButton问题 2022-01-01
- 用 Swift 实现 UITextFieldDelegate 2022-01-01
- Android viewpager检测滑动超出范围 2022-01-01
- Android - 我如何找出用户有多少未读电子邮件? 2022-01-01
- 想使用ViewPager,无法识别android.support.*? 2022-01-01