android - 房间不使用 @Update(onConflict = OnConflictStrategy.REPLACE) 更新实体
问题描述
我的应用程序使用 Google Places API,我后来使用这些数据从 openweather 获取天气。我有一个SearchFragment
发生RecyclerView
这种情况的地方。
在里面SearchFragment
我观察到我得到的列表:
viewModel.predictions.observe(viewLifecycleOwner) {
citiesAdapter.submitList(it)
}
<...>
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_fragment_weather, menu)
<...>
searchView.onQueryTextChanged {
viewModel.searchQuery.value = it
}
}
我的viewModel
:
class SearchViewModel @Inject constructor(
private val repository: AutocompleteRepository,
private val weatherRepository: WeatherRepository
) : ViewModel() {
fun provideClient(client: PlacesClient) {
repository.provideClient(client)
}
val searchQuery = MutableStateFlow("")
private val autocompleteFlow = searchQuery.flatMapLatest {
repository.getPredictions(it)
}
val predictions = autocompleteFlow.asLiveData()
fun onAddPlace(place: PlacesPrediction, added: Boolean) {
viewModelScope.launch {
repository.update(place, added)
if (added) weatherRepository.addWeather(place)
else weatherRepository.delete(place)
}
}
fun onDestroy() = viewModelScope.launch {repository.clearDb()}
}
在里面adapter
我像这样绑定我的项目:
inner class CityViewHolder(private val binding: ItemCityToAddBinding) : RecyclerView.ViewHolder(binding.root) {
init {
binding.apply {
btnAdd.setOnClickListener {
val position = adapterPosition
if (position != RecyclerView.NO_POSITION) {
val place = getItem(position)
btnAdd.animate().rotation(if (place.isAdded) 45f else 0f).start()
println("Current item state (isAdded): ${place.isAdded}")
listener.onAddClick(place, !place.isAdded)
}
}
}
}
fun bind(prediction : PlacesPrediction) {
binding.apply {
val cityName = prediction.fullText.split(", ")[0]
locationName.text = cityName
fullName.text = prediction.fullText
btnAdd.animate().rotation(if (prediction.isAdded) 45f else 0f).start()
}
}
}
从我的片段中listener
作为参数传递给我的适配器的位置:
override fun onAddClick(place: PlacesPrediction, isAdded: Boolean) {
viewModel.onAddPlace(place, isAdded)
println("Parameter passed to onClick: $isAdded, placeId = ${place.placeId}")
}
<...>
val citiesAdapter = CitiesAdapter(this)
我repository
的update()
方法是这样的:
suspend fun update(place: PlacesPrediction, added: Boolean) =
database.dao().update(place.copy(isAdded = added))
最后,我dao
的update
:
@Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun update(prediction: PlacesPrediction)
这一切都与PlacesPrediction
课堂有关,这里是:
@Entity(tableName = "autocomplete_table")
data class PlacesPrediction(
val fullText: String,
val latitude: Double,
val longitude: Double,
val placeId: String,
val isAdded: Boolean = false
) {
@PrimaryKey(autoGenerate = true) var id: Int = 0
}
所以,我的问题是PlacesPrediction
我的数据库中的条目没有得到更新。实际上,我想用上面提供的代码更新的唯一字段是isAdded
,但在我按下btnAdd
列表项后它保持不变。我使用 Android Studio 的 Database Inspector 来验证这一点。
我尝试@Insert
像这样使用:
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(prediction: PlacesPrediction)
suspend fun update(place: PlacesPrediction, added: Boolean) =
database.dao().insert(place.copy(isAdded = added))
但奇怪的是它只插入了一个副本place
,我点击的原始项目保持不变。
解决方法
只有当我破解我的方式时,我才会得到所需的行为:
@Entity(tableName = "autocomplete_table")
data class PlacesPrediction(
val fullText: String,
val latitude: Double,
val longitude: Double,
val placeId: String,
var isAdded: Boolean = false,
@PrimaryKey(autoGenerate = true) var id: Int = 0
)
suspend fun update(place: PlacesPrediction, added: Boolean) =
database.dao().insert(place.copy(isAdded = added, id = place.id))
而且我根本不喜欢这个解决方案。所以我的问题是:我如何@Update
工作?
解决方案
您可能已经理解,copy
数据类的生成方法会忽略在构造函数之外声明的所有成员。因此place.copy(isAdded = added)
将生成所有构造函数参数的副本,但将 id 保留为默认值 0,这意味着应该插入一个新元素,而不是更新现有元素。
现在这是我个人的看法:
将 id 作为构造函数参数是最优雅的解决方案,因为更新将开箱即用。
但是,如果您非常不喜欢它,也许扩展功能可能会帮助您:
inline fun PlacesPrediction.preserveId(copyBuilder: PlacesPrediction.() -> PlacesPrediction): PlacesPrediction{
val copy = copyBuilder(this)
copy.id = this.id
return copy
}
//usage
suspend fun update(place: PlacesPrediction, added: Boolean) =
database.dao().insert(place.preserveId { copy(isAdded = added) })
推荐阅读
- r - 日期数学不会在 R 与 Redshift 中产生相同的结果
- reactjs - officejs 反应 - 我如何添加另一个页面?
- macos - 如何使用单个命令从 dmg 静默安装 MacOS .app?
- angular - 如何为 Angular ngrx 商店制作“reducer enhancer”以进行撤消/重做
- azure-sql-database - 从 Azure 尝试时备份失败
- php - 无法为 PHP 7.2 安装 MongoDB
- c# - foreach 循环中的两种不同数据类型
- amazon-web-services - 如何修复 aws 区域错误“ValueError:必须使用 SageMaker 支持的区域设置本地 AWS 配置”
- xml - 在 SSRS 中使用 ElementPath 处理重复的 XML 元素
- django - 如何获取相关模型对象的某些字段值并将其保存到另一个?