Kus*_*ave 5 android android-jetpack android-jetpack-compose
我正在创建使用 jetpack compose 和 mvvm 的演示项目,我创建了包含用户列表的模型类..这些用户显示在列表中,顶部有一个按钮,单击时将新用户添加到列表中...当用户单击按钮时,lambda 会更新有关它的活动,活动会调用 viewmodel 将数据添加到列表并使用 livedata 更新回活动,现在模型收到新数据后,它不会更新有关它的可组合功能,因此不会更新 ui列表未更新.. 这是代码
@Model
data class UsersState(var users: ArrayList<UserModel> = ArrayList())
Run Code Online (Sandbox Code Playgroud)
活动
class MainActivity : AppCompatActivity() {
private val usersState: UsersState = UsersState()
private val usersListViewModel: UsersListViewModel = UsersListViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
usersListViewModel.getUsers().observe(this, Observer {
usersState.users.addAll(it)
})
usersListViewModel.addUsers()
setContent {
UsersListUi.addList(
usersState,
onAddClick = { usersListViewModel.addNewUser() },
onRemoveClick = { usersListViewModel.removeFirstUser() })
}
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型
class UsersListViewModel {
private val usersList: MutableLiveData<ArrayList<UserModel>> by lazy {
MutableLiveData<ArrayList<UserModel>>()
}
private val users: ArrayList<UserModel> = ArrayList()
fun addUsers() {
users.add(UserModel("jon", "doe", "android developer"))
users.add(UserModel("john", "doe", "flutter developer"))
users.add(UserModel("jonn", "dove", "ios developer"))
usersList.value = users
}
fun getUsers(): MutableLiveData<ArrayList<UserModel>> {
return usersList
}
fun addNewUser() {
users.add(UserModel("jony", "dove", "ruby developer"))
usersList.value = users
}
fun removeFirstUser() {
if (!users.isNullOrEmpty()) {
users.removeAt(0)
usersList.value = users
}
}
}
Run Code Online (Sandbox Code Playgroud)
可组合函数
@Composable
fun addList(state: UsersState, onAddClick: () -> Unit, onRemoveClick: () -> Unit) {
MaterialTheme {
FlexColumn {
inflexible {
// Item height will be equal content height
TopAppBar( // App Bar with title
title = { Text("Users") }
)
FlexRow() {
expanded(flex = 1f) {
Button(
text = "add",
onClick = { onAddClick.invoke() },
style = OutlinedButtonStyle()
)
}
expanded(flex = 1f) {
Button(
text = "sub",
onClick = { onRemoveClick.invoke() },
style = OutlinedButtonStyle()
)
}
}
VerticalScroller {
Column {
state.users.forEach {
Column {
Row {
Text(text = it.userName)
WidthSpacer(width = 2.dp)
Text(text = it.userSurName)
}
Text(text = it.userJob)
}
Divider(color = Color.Black, height = 1.dp)
}
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
整个源代码可以在这里找到
我不确定我是否做错了什么,还是因为 jetpack compose 仍处于开发者预览版中,所以非常感谢您的帮助..谢谢
哎呀!
来自 Android Devrel 的 Sean 在这里。这不是更新的主要原因是 ArrayListUserState.users是不可观察的——它只是一个普通的,ArrayList所以它不会更新 compose。
看起来这可能有效,因为UserState是 annotated @Model,这使得 Compose 可以自动观察到事物。但是,可观察性仅适用于一层深度。这是一个永远不会触发重组的示例:
class ModelState(var username: String, var email: String)
@Model
class MyImmutableModel(val state: ModelState())
Run Code Online (Sandbox Code Playgroud)
由于state变量是不可变的 ( val),因此 Compose 永远不会在您更改email或时触发重组username。这是因为@Model仅适用于注释的类的属性。在这个例子state中,在 Compose 中是可观察的,但username和email只是常规字符串。
在这种情况下,您已经有一个LiveDatafrom getUsers()– 您可以在 compose 中观察到。我们还没有在开发版本中发布 Compose 观察,但是在我们发布观察方法之前,可以使用效果编写一个观察方法。只记得删除 中的观察者onDispose {}。
如果您使用任何其他可观察类型,如Flow、Flowable等,这也是正确的。您可以将它们直接传递给@Composable函数并观察它们的效果,而无需引入中间@Model类。
许多开发人员更喜欢 UI 状态的不可变数据类型(像 MVI 这样的模式鼓励这样做)。您可以更新您的示例以使用不可变列表,然后为了更改列表,您必须分配给usersCompose 可观察的属性。
@Model
class UsersState(var users: List<UserModel> = listOf())
Run Code Online (Sandbox Code Playgroud)
然后当你想更新它时,你必须分配users变量:
val usersState = UsersState()
// ...
fun addUsers(newUsers: List<UserModel>) {
usersState.users = usersState.users + newUsers
// performance note: note this allocates a new list every time on the main thread
// which may be OK if this is rarely called and lists are small
// it's too expensive for large lists or if this is called often
}
Run Code Online (Sandbox Code Playgroud)
每当将新List<UserModel分配给 时users,这将始终触发重新组合,并且由于在分配列表后无法编辑列表,因此 UI 将始终显示当前状态。
在这种情况下,由于数据结构是List您正在连接的不可变类型的性能可能是不可接受的。但是,如果您持有一个不可变的data class选项,那么这个选项是一个不错的选择,因此我将其包含在内以保持完整性。
对于这个用例,Compose 有一个特殊的可观察列表类型。您可以使用代替 anArrayList并且对列表的任何更改都可以通过 compose 观察到。
@Model
class UsersState(val users: ModelList<UserModel> = ModelList())
Run Code Online (Sandbox Code Playgroud)
如果您使用ModelList在 Activity 中编写的其余代码将正常工作,并且Compose将能够users直接观察到更改。
值得注意的是,您可以嵌套@Model类,这就是该ModelList版本的工作方式。回到开头的示例,如果您将两个类都注释为 @Model,那么所有属性都将在 Compose 中可见。
@Model
class ModelState(var username: String, var email: String)
@Model
class MyModel(var state: ModelState())
Run Code Online (Sandbox Code Playgroud)
注意:此版本添加@Model到ModelState,并且还允许重新分配状态MyModel
因为@Model使被 compose 注释的类的所有属性都可观察,state, username, 和email都将是可观察的。
@Model在此代码中完全避免(选项 #0)将避免仅为 Compose 引入重复的模型层。由于您已经在 a 中保持状态ViewModel并通过它公开它,因此LiveData您可以LiveData直接传递 compose 并在那里观察它。这将是我的第一选择。
如果您确实想使用@Model来表示可变列表,请使用ModelList选项 #2。
您可能还想更改 ViewModel 以保存 MutableLiveData 引用。目前 ViewModel 持有的列表是不可观察的。的介绍,ViewModel并LiveData从Android的架构组件检查了Android的基础课程。
您的模型没有被观察到,因此更改不会得到反映。 在本文的“将其全部放在一起”部分下添加了列表。
val list = +memo{ calculation: () -> T}
Run Code Online (Sandbox Code Playgroud)
您的列表示例:
@Composable
fun test(supplier: UserState) {
val list = +memo{supplier.users}
ListConsumer(list){
/* Do other stuff for your usecase */
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2944 次 |
| 最近记录: |