我正在使用Jetpack Compose开发Android应用程序。该应用程序显示项目列表。它还有一个包含搜索栏的顶部栏。
我们有3个组件:项目列表、搜索栏组件和应用程序栏(应用程序栏包含搜索栏)。
相同的 ViewModel 类注入到可组合列表和可组合搜索栏(使用 Hilt)中。视图模型具有以下项列表:
var项目由MutableStateOf
以及由搜索栏调用的搜索函数,用于过滤这些项目。
问题如下:搜索项目时,列表可组合无法重新组合。
铌:
因此,似乎只有当搜索栏在列表中时,列表才会重新组合。
当搜索栏在应用程序栏中时,如何使其工作?
谢谢你,
编辑:通过在初始化ViewModel时生成一个随机值,Hilt似乎在Searchbar可组合和项目可组合中注入了两个不同的实例。
是否可以将ViewModel作为单例注入?或者我应该将数据保存在存储库中,然后将这些数据提供给ViewModel?
下面是不同类的代码:
Searchbar.kt
@Composable
fun SearchBar(itemViewModel: ItemViewModel = hiltViewModel()){
var searchText by remember { mutableStateOf("") }
BasicTextField(
singleLine = true,
cursorBrush = SolidColor(Color.White),
value = searchText,
onValueChange = {
searchText = it
itemViewModel.searchByLabel(it)
},
modifier = Modifier
.fillMaxWidth()
.height(28.dp),
textStyle = LocalTextStyle.current.copy(
color = Color.White,
fontSize = MaterialTheme.typography.body2.fontSize
),
decorationBox = { innerTextField ->
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
Icon(
Icons.Filled.Search,
contentDescription = "Search"
)
Column(Modifier.weight(1f)) {
Box(
modifier = Modifier.fillMaxWidth()
) {
if (searchText.isEmpty()) {
Text(
"Search",
style = LocalTextStyle.current.copy(
color = Color.White.copy(alpha = 0.7f),
fontSize = MaterialTheme.typography.body2.fontSize
)
)
}
innerTextField()
}
}
if (searchText.isNotEmpty()) {
IconButton(onClick = { searchText = "" }) {
Icon(Icons.Filled.Cancel, contentDescription = "Delete")
}
}
}
}
)
}
项目.kt
@Composable
fun Items(
navController: NavController,
itemViewModel: ItemViewModel = hiltViewModel(),
){
val items = itemViewModel.items
items?.let { items ->
LazyColumn(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
items(items) { item ->
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
navController.navigate("items/${item.id}")
},
Arrangement.spacedBy(8.dp)
) {
Text(item.label)
}
}
}
} ?: run {
Text(
text = "No protocols",
modifier = Modifier.fillMaxWidth()
)
}
}
ItemViewModel.kt
@HiltViewModel
class ItemViewModel @Inject constructor(private val repository: ItemRepository) : ViewModel() {
var items by mutableStateOf<List<Item>?>(null)
init{ loadItems() }
private fun loadItems(){
viewModelScope.launch {
items = repository.getItems()
}
}
fun searchByLabel(value: String){
viewModelScope.launch {
items = repository.search(value)
}
}
}
ItemRepository.kt
class ItemRepository(){
suspend fun getItems(): List<Item>? {
return listOf(Item(1, "Label 1"), Item(2, "Label 2"), Item(3, "Label 3"))
}
suspend fun search(value: String): List<Item>? {
return getItems()?.filter { it.label.lowercase().contains(value.lowercase())}
}
}
Item.kt
data class Item(var id: Int, var label: String){}
我最终将数据存储在存储库中,该存储库作为单例注入。这样,即使创建了ViewModel的多个实例,它们仍然访问相同的数据。