提问者:小点点

从不同的可组合组件更新视图模型时,不可组合组件


我正在使用Jetpack Compose开发Android应用程序。该应用程序显示项目列表。它还有一个包含搜索栏的顶部栏。

我们有3个组件:项目列表、搜索栏组件和应用程序栏(应用程序栏包含搜索栏)。

相同的 ViewModel 类注入到可组合列表和可组合搜索栏(使用 Hilt)中。视图模型具有以下项列表:

var项目由MutableStateOf

以及由搜索栏调用的搜索函数,用于过滤这些项目。

问题如下:搜索项目时,列表可组合无法重新组合。

铌:

    < li >我记录了搜索功能的输出,因此我确信该功能运行正常。 < li >当将可组合搜索栏放入包含项目列表的同一个可组合搜索栏时,搜索按预期进行。

因此,似乎只有当搜索栏在列表中时,列表才会重新组合。

当搜索栏在应用程序栏中时,如何使其工作?

谢谢你,

编辑:通过在初始化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){}

共1个答案

匿名用户

我最终将数据存储在存储库中,该存储库作为单例注入。这样,即使创建了ViewModel的多个实例,它们仍然访问相同的数据。