房间没有使用@Update(onConflict = OnConflictStrategy.REPLACE)更新实体.&



我的应用程序使用Google Places API,我稍后使用该API从openweather获取天气数据。我有一个SearchFragmentRecyclerView在这里发生。

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
}
}

MyviewModel:

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)

我的repositoryupdate()方法看起来像这样:

suspend fun update(place: PlacesPrediction, added: Boolean) =
database.dao().update(place.copy(isAdded = added))

最后,我的daoupdate:

@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的数据库检查器来验证。

我试着用@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) })

相关内容

  • 没有找到相关文章