Jetpack Compose:使用 TextField 修改 Room 数据类

nba*_*man 3 android state kotlin android-jetpack android-jetpack-compose

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

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) })
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  1. 虽然LiveData有一个名为 的函数observeAsState(),但它返回State<T>而不是MutableState<T>,这意味着您不能使用 修改它TextFields。因此,这不起作用:
    • remember { personFromDb.observeAsState()}
  2. 您不能从数据库中获取,因为您的组件将在返回 Room 查询之前呈现,这意味着您不能执行此操作,因为类.copy()实例将被记住为: PersonPersonnull
    • remember { mutableStateOf(findPersonQueryResult.value) }

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

2ja*_*222 5

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

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))}
    )
}
Run Code Online (Sandbox Code Playgroud)