我的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
可能会解决所有问题!