【问题标题】:Jetpack Compose: Modify Room data class using TextFieldJetpack Compose:使用 TextField 修改 Room 数据类
【发布时间】:2020-09-23 12:46:27
【问题描述】:

使用EditText 修改简单值和data classes 相当简单,通常如下所示:

data class Person(var firstName: String, var lastName: Int)

// ...

val (person, setPerson) = remember { mutableStateOf(Person()) }

// common `onChange` function handles both class properties, ensuring maximum code re-use
fun <T> onChange(field: KMutableProperty1<Person, T>, value: T) {
    val nextPerson = person.copy()
    field.set(nextPerson, value)
    setPerson(nextPerson)
}

// text field for first name
TextField(
    value = person.firstName,
    onChange = { it -> onChange(Person::firstName, it) })

// text field for last name name
TextField(
    value = person.lastName,
    onChange = { it -> onChange(Person::lastName, it) })

如您所见,此示例中的代码具有高度可重用性:感谢 Kotlin 的反射功能,我们可以使用单个 onChange 函数来修改此类中的每个属性。

但是,当Person 类不是从头开始实例化,而是通过Room 从磁盘中提取时,就会出现问题。例如,PersonDao 可能包含一个 `findOne() 函数,如下所示:

@Query("SELECT * FROM peopleTable WHERE id=:personId LIMIT 1")
fun findOne(personId: String): LiveData<Person>

但是,由于多种原因,您不能真正在 remember {} 中使用此 LiveData:

  1. 虽然LiveData 有一个名为observeAsState() 的函数,但它返回State&lt;T&gt; 而不是MutableState&lt;T&gt;,这意味着您不能使用TextFields 对其进行修改。因此,这不起作用:
    • remember { personFromDb.observeAsState()}
  2. 你不能.copy()你从你的数据库中得到Person,因为你的组件将在返回房间查询之前呈现,这意味着你不能这样做,因为Person类实例将被记住为@987654339 @:
    • remember { mutableStateOf(findPersonQueryResult.value) }

鉴于此,处理此问题的正确方法是什么?是否应该将包含TextFields 的组件包装在另一个处理 Room 查询的组件中,并且只在查询返回时显示表单? LiveData&lt;Person&gt; 这个案例会是什么样子?

【问题讨论】:

  • 至第 2 点:当您的状态发生变化时,您可以使用 remember(yourState [e.g personFromDb.observeAsState()]) {mutableStateOf(findPersonQueryResult.value)} 计算再次完成

标签: android kotlin state android-jetpack android-jetpack-compose


【解决方案1】:

我会用一个副本和一个不可变的数据类来做

typealias PersonID = Long?
@Entity
data class Person(val firstName: String, val lastName: String) {
    @PrimaryKey(autoGenerate = true)
    val personID: PersonID = null
}
//VM or sth
object VM {
    val liveData: LiveData<Person> = MutableLiveData() // your db call
    val personDao: PersonDao? = null // Pretending it exists
}

@Dao
abstract class PersonDao {
    abstract fun upsert(person: Person)
}

@Composable
fun test() {
    val personState = VM.liveData.observeAsState(Person("", ""))
    TextField(
        value = personState.value.firstName,
        onValueChange = { fName -> VM.personDao?.upsert(personState.value.copy(firstName = fName))}
    )
}

【讨论】:

    猜你喜欢
    • 2021-01-05
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多