【发布时间】:2021-03-02 18:01:47
【问题描述】:
我的应用程序使用 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
}
所以,我的问题是我的数据库中的PlacesPredictions 条目没有得到更新。实际上,我想用上面提供的代码更新的唯一字段是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 工作?
【问题讨论】:
标签: android android-room android-mvvm