当 ViewModel 从不同的 Composable 更新时,Composable 不会重新组合

问题描述 投票:0回答:2

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

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

相同的 ViewModel 类被注入到列表可组合项和搜索栏可组合项中(使用 Hilt)。 ViewModel 有项目列表:

var items by mutableStateOf<List<Item>?>(null)

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

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

注意:

  • 我记录了搜索函数的输出,因此我确信该函数运行正常。
  • 将搜索栏可组合项放置在包含项目列表的同一可组合项中时,搜索将按预期工作。

所以看起来列表只有当搜索栏位于其中时才会重新组合。

当搜索栏位于应用栏中时如何使其工作?

谢谢你,

编辑: 通过在初始化 ViewModel 时生成随机值,Hilt 似乎在 Searchbar 可组合项和可组合项中注入了两个不同的实例。

是否可以将 ViewModel 作为单例注入?或者我应该将数据保存在存储库中,然后将这些数据提供给 ViewModel?

这是不同类的代码:

搜索栏.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())}
    }
}

项目.kt

data class Item(var id: Int, var label: String){}
android viewmodel android-jetpack-compose android-jetpack
2个回答
0
投票

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


0
投票

我认为在重构视图模型时创建新实例

© www.soinside.com 2019 - 2024. All rights reserved.