Jetpack撰写:使用TextField

时间:2020-09-23 12:46:27

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

使用data class修改简单值和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) })

如您所见,此示例中的代码具有很高的可重用性:由于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<T>而不是MutableState<T>,这意味着您不能使用TextFields对其进行修改。因此,这不起作用:
    • remember { personFromDb.observeAsState()}
  2. 您无法.copy()从数据库中获得的Person,因为组件将在返回Room查询之前呈现,这意味着您无法执行此操作,因为Person类实例将被记住为null
    • remember { mutableStateOf(findPersonQueryResult.value) }

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

1 个答案:

答案 0 :(得分: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))}
    )
}