如何可靠地更新特定RecyclerView项上的数据?



我的RecyclerView Item中的日期/时间只在每次更改时更新,而不是每次更改。当前进程为:

  • 用户通过日期/时间选择器更新时间
  • 更改保存到房间数据库
  • 我的片段的"提醒";触发LiveData观察者,它调用适配器的覆盖的submitList函数
  • 对于每~2次更改,submitList认为新旧列表是相同的,因为旧列表已经以某种方式更新以反映新的更改,即使旧列表(mRemindersList)是适配器私有的,所以我不确定它是如何悄悄地更新的。

例子:

我把时间从15:21改成了21:21。在下面的对话框中点击OK后,RecyclerView项目仍然显示15:21的旧时间:时间为15:21的RecyclerView项目图片,新选择的时间为21:21

来自submitList的日志:

2022-05-26 17:57:30.314 6461-6461/com.example.ewmreminders V/ReminderListAdapter:165:submitList: Are the two lists the same? true
2022-05-26 17:57:30.315 6461-6461/com.example.ewmreminders V/ReminderListAdapter:168:submitList: Old list (size: 1): [Reminder(id=51, hour=21, minute=21)]
2022-05-26 17:57:30.315 6461-6461/com.example.ewmreminders V/ReminderListAdapter:169:submitList: New list (size: 1): [Reminder(id=51, hour=21, minute=21)]

如果我再次点击时间从我的RecyclerView项目,TimePickerDialog正确默认时间为21:21(所以某处它知道时间更新…)如果我将时间更改为18:21,只要我点击OK,时间就会更新:时间正确更新为18:21的RecyclerView Item图片

来自submitList的日志:

2022-05-26 18:03:50.931 6461-6461/com.example.ewmreminders V/ReminderListAdapter:165:submitList: Are the two lists the same? false
2022-05-26 18:03:50.932 6461-6461/com.example.ewmreminders V/ReminderListAdapter:168:submitList: Old list (size: 1): [Reminder(id=51, hour=21, minute=21)]
2022-05-26 18:03:50.932 6461-6461/com.example.ewmreminders V/ReminderListAdapter:169:submitList: New list (size: 1): [Reminder(id=51, hour=18, minute=21)]

:
适配器:

class ReminderListAdapter(private val timeClickListener: ReminderClickListener,
private val reminderListViewModel: ReminderListViewModel,
val activity: MainActivity,
val reminderDatabaseDao: ReminderDatabaseDao):
ListAdapter<Reminder, ReminderListAdapter.ReminderListViewHolder>(DiffCallback),
ItemTouchHelperAdapter
{
private var mRemindersList = mutableListOf<Reminder>()
override fun submitList(list: List<Reminder>?) {
Timber.v("Are the two lists the same? ${mRemindersList == list?.toMutableList()}")
Timber.v("Old list (size: ${mRemindersList.size}): $mRemindersList")
Timber.v("New list (size: ${list?.size}): $list")
mRemindersList = list.toMutableList() //DiffUtil needs a new list to compare to
super.submitList(mRemindersList)
}
}

片段:

class ReminderListFragment : Fragment() {
private lateinit var reminderListViewModel: ReminderListViewModel
lateinit var adapter: ReminderListAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding: FragmentReminderListBinding = DataBindingUtil.inflate(
inflater, R.layout.fragment_reminder_list, container, false)
val application = requireNotNull(this.activity).application
val reminderDatabaseDao = ReminderDatabase.getInstance(application).reminderDatabaseDao
val viewModelFactory = ReminderListViewModelFactory(reminderDatabaseDao, application)
reminderListViewModel =
ViewModelProvider(this, viewModelFactory)[ReminderListViewModel::class.java] //.get() and [] are the same thing
binding.reminderListViewModel = reminderListViewModel
binding.lifecycleOwner = this
val manager = LinearLayoutManager(this.context)
binding.remindersList.layoutManager = manager

adapter = ReminderListAdapter(
ReminderClickListener(application) { reminder, position ->
val defaultReminderTime: LocalTime = LocalTime.of(reminder.hour!!, reminder.minute!!)
val timeClickListener =
TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute ->
val selectedTime = LocalTime.of(hourOfDay, minute)
reminderListViewModel.setTime(reminder, selectedTime) //updates the database
//                        adapter.notifyItemChanged(position)
}
val tP = TimePickerDialogPlus(context, timeClickListener, defaultReminderTime.hour, defaultReminderTime.minute, true) {
Timber.v("User clicked the Clear button")
reminderListViewModel.setTime(reminder, null)
}
tP.show()
},
reminderListViewModel,
activity as MainActivity,
reminderDatabaseDao)
binding.remindersList.adapter = adapter

reminderListViewModel.reminders.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it.toMutableList())
}
})

return binding.root
}
}

视图模型:

class ReminderListViewModel(val reminderDatabaseDao: ReminderDatabaseDao, application: Application) : AndroidViewModel(application) {
fun setTime(reminder: Reminder, selectedTime: LocalTime?) {
reminder.hour = selectedTime?.hour
reminder.minute = selectedTime?.minute
reminder.save(getApplication()) //eventually calls reminderDatabaseDao.update
}
var reminders = reminderDatabaseDao.getAllReminders()
}
Dao:

interface ReminderDatabaseDao {
@Update
fun update(reminder: Reminder)
@Query("select * ...etc...")
fun getAllReminders() : LiveData<List<Reminder>>
}

认为

  • 我尝试调用adapter.notifyItemChanged(position),但这没有改变任何

是的,在虚拟机的setTime函数中,你传递了一个Reminder实例并改变了它的数据,改变了对象本身:

fun setTime(reminder: Reminder, selectedTime: LocalTime?) {
reminder.hour = selectedTime?.hour
reminder.minute = selectedTime?.minute

和你传入的Reminder适配器的内部列表中的对象之一:

adapter = ReminderListAdapter(
ReminderClickListener(application) { reminder, position ->
...
reminderListViewModel.setTime(reminder, selectedTime)

所以你显式地将适配器中的Reminder更新为21:21(这不会在视觉上更新,因为适配器还不知道任何关于更改的信息)。


setTime更改了Reminder对象后,它使用它来更新DB:

reminder.save(getApplication())

更新记录,将新列表推送到getAllReminders()抓取的LiveData,并且应该包含唯一的Reminder实例。但是请记住,您已经通过更新Reminder更改了适配器的内部列表。从DB中得到的列表将与旧的列表相同,只是Reminder中的一个时间发生了变化,对吗?

由于您以相同的方式更改了适配器的内部列表,因此数据将匹配-列表将看起来相同(我假设您的diff将两个Reminder处理具有相同数据的"相同",如果它们是数据类并检查是否相等,则是的)。所以适配器不需要更新显示——就它而言,什么都没有改变。


您的对话框显示正确的时间,因为时间已经在Reminder上设置了-适配器只是还没有显示它。我不知道为什么它会工作与完全相同的步骤每二次-你可能需要设置一些断点在有用的地方(例如在setTime,你的reminders上的观察者,在你的对话框内)和调试应用程序,看看到底发生了什么在那里,因为它正在运行。


很抱歉长答案,但我想解释为什么你看到这个问题-你有效地更新适配器的内部列表一个在DB/视图模型在同一时间,所以他们总是匹配。您可能可以通过而不是改变您传入的Reminder来修复它-只需复制,更改其上的时间,并将保存为到DB。不要碰旧的,这样就能反映旧的状态。如果你使用的是数据类,你可以直接使用

reminder.copy(
hour = selectedTime?.hour,
minute = selectedTime?.minute
).save(application) // if you make application a val in your VM constructor you can access it here

可能会解决所有问题!

相关内容

  • 没有找到相关文章

最新更新