【发布时间】:2020-10-19 11:14:24
【问题描述】:
学校项目,我对 Android 开发还很陌生。
问题
我在 保存人员片段 中有一个带有 onClick 侦听器的按钮,它将人员数据保存到数据库中。一切正常,除了出于某种原因第一次点击它不会返回插入的行 ID,但它会在第二次点击之后返回。
在继续下一个片段之前,我真的需要这个 ID。
不确定这是否重要,但每当我返回(重新加载)此保存人员片段时,行为始终相同,即第一次点击始终无法捕获插入的行 ID。 p>
输入数据:
first name = John
last name = Smith
仅出于演示目的,如果我尝试使用此按钮 3 次插入人员数据(返回的插入 ID 在日志中),我将在数据库中获取名称为 John Smith 的所有 3 行,但第一个插入的未捕获行ID(默认初始化值为0),请参阅下面的日志:
日志
2020-10-19 12:49:20.320 25927-25927/ee.taltech.mobile.contacts D/TEST_ADD_PERSON_ID: insertedPersonId: 0
2020-10-19 12:49:40.153 25927-25927/ee.taltech.mobile.contacts D/TEST_ADD_PERSON_ID: insertedPersonId: 5
2020-10-19 12:49:40.928 25927-25927/ee.taltech.mobile.contacts D/TEST_ADD_PERSON_ID: insertedPersonId: 6
已编辑的原始帖子
按照 cmets 的建议,我正在尝试使用 LiveData 和观察者的方式,但我仍然有点卡住。
设置
以下是当前设置。
实体
@Entity(tableName = "person")
data class Person(
@PrimaryKey(autoGenerate = true)
val id: Int,
DAO
@Dao
interface PersonDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addPerson(person: Person): Long
存储库
class PersonRepository(private val personDao: PersonDao) {
val readAllPersonData: LiveData<List<Person>> = personDao.readAllPersonData()
suspend fun addPerson(person: Person): Long {
return personDao.addPerson(person)
}
视图模型
我不确定我在这里做的是否正确。我在这里逐步分解并创建了单独的变量insertedPersonILiveData 和insertedPersonId。
如何将返回的行 id 传递给insertedPersonILiveData?
class PersonViewModel(application: Application) : AndroidViewModel(application) {
var insertedPersonILiveData: LiveData<Long> = MutableLiveData<Long>()
var insertedPersonId: Long = 0L
val readAllPersonData: LiveData<List<Person>>
private val repository: PersonRepository
init {
val personDao = ContactDatabase.getDatabase(application).personDao()
repository = PersonRepository(personDao)
readAllPersonData = repository.readAllPersonData
}
suspend fun addPerson(person: Person) = viewModelScope.launch {
insertedPersonId = repository.addPerson(person)
// ****************************************************************
// insertedPersonILiveData = insertedPersonId (what to do here) ???
// ****************************************************************
}
保存人物片段 这就是我通过 modelView 调用 addPerson 的方式。
val person = Person(0, firstName, lastName)
lifecycleScope.launch {
personViewModel.addPerson(person)
}
Log.d("TEST_ADD_PERSON_ID","insertedPersonId: ${personViewModel.insertedPersonId}")
这就是我做观察者的方式(不确定它是否正确)。
val returnedIdListener: LiveData<Long> = personViewModel.insertedPersonILiveData
returnedIdListener.observe(viewLifecycleOwner, Observer<Long> { id: Long ->
goToAddContactFragment(id)
})
private fun goToAddContactFragment(id: Long) {
Log.d("TEST_ADD_PERSON_ID", "id: " + id)
}
创建数据库
@Database(
entities = [Person::class, Contact::class, ContactType::class],
views = [ContactDetails::class],
version = 1,
exportSchema = false
)
abstract class ContactDatabase : RoomDatabase() {
abstract fun personDao(): PersonDao
abstract fun contactTypeDao(): ContactTypeDao
abstract fun contactDao(): ContactDao
abstract fun contactDetailsDao(): ContactDetailsDao
companion object {
// For Singleton instantiation
@Volatile
private var instance: ContactDatabase? = null
fun getDatabase(context: Context): ContactDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}
private fun buildDatabase(context: Context): ContactDatabase {
return Room.databaseBuilder(context, ContactDatabase::class.java, "contacts_database")
.addCallback(
object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build()
WorkManager.getInstance(context).enqueue(request)
}
}
)
.build()
}
}
}
【问题讨论】:
-
同一个Fragment好像有多个ViewModel,为什么会这样呢?如果您在同一个 ViewModel 中同时拥有人员和联系人存储库,则不需要通过 Fragment 传递 id
-
@Stachu 很好,我之前只是在玩一些东西,然后忘记了。我已将其从代码中删除。也相应地更新了帖子。作为记录,我每个片段只使用 1 个模型视图。不管怎样,问题依然存在。它不会在第一次点击时捕获 id。有什么想法吗?
-
我的猜测是日志在
insertedPersonId更新之前运行,所以即使它实际上已经运行了两次,你也只能看到更新前的值。您可以将insertedPersonId设置为 LiveData并使用观察者触发更改。另一种选择是在 viewmodel 中使 addPerson成为挂起函数,然后从例如调用它。addPersonAndProcessId。什么更适合你? -
@Stachu 我真的很想学习并了解如何使用观察者方法(必须学习它)。现在我正在努力理解如何在
PersonViewModel类中设置insertedPersonId。我的意思是var insertedPersonId: LiveData<Long> = ...这里发生了什么?如何初步评估它? -
会是这样吗?
var insertedPersonId: LiveData<Long> = MutableLiveData<Long>()
标签: kotlin mvvm android-room sql-insert