我们可以将 viewmodel 作为参数传递给另一个 compose 函数吗?

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

我有点困惑。我们可以将 viewmodel 传递给另一个可组合函数吗?如果不是,那么将任何视图模型访问另一个函数的好方法是什么?我在这里给出代码片段,以便您可以更好地理解。单击对话框中的“保存”按钮后,我正在传递视图模型以访问房间数据库插入功能之一。

这是我的主要功能

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun homeScreen(modifier: Modifier, todoViewModel: todoViewModel = viewModel()) {

    val dataList by todoViewModel.getAllTodo.collectAsState()

    val scrollBehavior = TopAppBarDefaults
        .pinnedScrollBehavior(rememberTopAppBarState())



    val openDialog = remember { mutableStateOf(true) }

    Scaffold(modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),

        topBar = {
            CenterAlignedTopAppBar(
                colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                    containerColor = Color.Black,
                    titleContentColor = Color.White
                ),
                title = {
                    Text(
                        "TO DO LISTS",
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                    )
                },
                actions = {
                    IconButton(onClick = { dialogBox(todoViewModel,openDialog) }){
                        Icon(
                            imageVector = Icons.Filled.Add,
                            contentDescription = "You have to add new todo work",
                            tint = Color.White
                        )
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ){
        Column(modifier= modifier.padding(it)) {

            LazyColumn {
                items(dataList){list ->

                    todoItems( data = list)

                }
            }

        }
    }


}

这是我的对话框。

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun dialogBox(todoViewModel: todoViewModel, openDialog: MutableState<Boolean>){

    var title by rememberSaveable{mutableStateOf("")}
    var description by rememberSaveable{mutableStateOf("")}

    Dialog(onDismissRequest = {openDialog.value = false}){

        Card(
            modifier = Modifier
                .fillMaxWidth()
                .height(200.dp)
                .padding(16.dp),
            shape = RoundedCornerShape(16.dp)
        ){

            Column(modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally) {
                OutlinedTextField(value = title,
                    onValueChange = { title = it },
                    label = { Text("Title") })
                Spacer(modifier = Modifier.padding(vertical = 12.dp))

                OutlinedTextField(value = description,
                    onValueChange = { description = it },
                    label = { Text("Description") })

                Row(modifier = Modifier
                    .fillMaxWidth(),
                    horizontalArrangement = Arrangement.Center) {

                    TextButton(onClick = {
                        todoViewModel.insertTodo(todoEntity(title = title, desciription = description))},
                        modifier = Modifier.padding(8.dp)){
                        Text("Save")
                    }
                    TextButton(onClick = {}, modifier = Modifier.padding(8.dp)){
                        Text("Dismiss")
                    }
                }
            }

        }

    }

}

我已经搜索了有关它的文章,但没有得到足够的文章可以更好地说明。

android kotlin android-jetpack-compose android-viewmodel
2个回答
0
投票

通过将整个

ViewModel
对象传递到可重用可组合项中,您可以将可重用可组合项紧密耦合
ViewModel
对象,这会阻止您在其他地方轻松使用它,或者在不需要存根
ViewModel 的情况下测试它
待用。

“Compose 和其他库”文档的 ViewModel 部分也指出了这一点

注意:由于其生命周期和作用域,您应该在屏幕级可组合项(即,靠近从导航图的活动、片段或目标调用的根可组合项)访问和调用 ViewModel 实例。 您永远不应该将 ViewModel 实例传递给其他可组合项,只传递它们所需的数据以及执行所需逻辑的函数作为参数。

因此,仅将您需要的内容从 ViewModel 传递到您的

dialogBox
可组合项(您还应该最好使用
PascalCase
作为方法名称,作为一个小挑剔)。据我所知,您只使用
insertTodo
中的
ViewModel
方法 - 这可以简化为
onSaveClick
lambda,然后您可以在使用此
 的地方调用 
insertTodo
 DialogBox
可组合。

当您可以在父可组合项中执行条件渲染时,也无需直接传递状态来处理条件渲染:

@Composable
fun DialogBox(..., openDialog: MutableState<Boolean>) { ... }

// VS
@Composable
fun DialogBox(...) { ... }

@Composable
fun HomeScreen(...) {
  if (openDialog.value) {
    DialogBox(...)
  }
}

无论如何,更新后的代码如下所示:

// "dialogBox" is too vague, I would probably name it something more
// specific like "NewTodoDialog"
@Composable
fun NewTodoDialog(
  onDismissRequest: () -> Unit,
  // Pass back the data here...
  // You could maybe make the data be contained in a data class,
  // something like "TodoItem" or similar
  onSaveClick: (title: String, description: String) -> Unit
) {
  var title by rememberSaveable { mutableStateOf(...) }
  var description by rememberSaveable { mutableStateOf(...) }

  Dialog(onDismissRequest = onDismissRequest) {
    // Dialog content...
    // ...
    // Dialog actions:
    Row(/* ... */) {
      TextButton(
        // You can pass back the data to be added here:
        onClick = { onSaveClick(title, description) },
        modifier = Modifier.padding(8.dp)
      ) {
        Text("Save")
      }
      // I've also updated the onClick of your dismiss button to _actually_
      // do something, like say request for the dialog to be dismissed
      TextButton(
        onClick = onDismissRequest,
        modifier = Modifier.padding(8.dp)
      ) {
        Text("Dismiss")
      }
    }
  }
}

// In the parent composable:
@Composable
fun HomeScreen(viewModel: YourViewModel, /* ... */) {
  var isDialogShown by rememberSaveable { mutableStateOf(false) }
  
  // Then you can conditionally render the dialog
  if (isDialogShown) {
    NewTodoDialog(
      // This would actually dismiss the dialog
      onDismissRequest = { isDialogShown = false },
      // Method references are more ideal here if the method + lambda
      // definitions are the same.
      // Otherwise, you'll have to call it manually in a lambda
      onSaveClick = viewModel::insertTodo
    )
  }
}

0
投票

来自 ViewModels 最佳实践,简而言之:

不要将 ViewModel 传递给其他类、函数或其他 UI 组件。因为平台管理它们,所以您应该让它们尽可能靠近平台。接近您的 Activity、片段或屏幕级可组合函数。这可以防止较低级别的组件访问超出其需要的数据和逻辑。

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