#android #kotlin #android-recyclerview #android-diffutils
#Android #kotlin #android-recyclerview #android-diffutils
Вопрос:
У меня есть RecyclerView изображений, которые пользователь может редактировать непосредственно в самом RecyclerView.
Часть редактирования в порядке и работает хорошо. Это делается на растровом изображении, которое накладывается на изображения, а затем сохраняет все изменения в файле изображения. Как только пользователь прокручивает recyclerview, растровое изображение уничтожается и становится невидимым.
Проблема в том, что любые изменения, вносимые пользователем, не видны при прокрутке. Они прокручивают СТАРОЕ изображение, а не ОТРЕДАКТИРОВАННОЕ изображение. Они должны выйти из утилизатора и вернуться в него, чтобы увидеть изменения.
Итак, как мне заставить RecyclerView перезагрузить изображение, которое было только что сохранено. Я использую Glide в своем адаптере, и, как вы можете видеть, у меня есть кэширование, основанное на времени сохранения изображения.
class InfinityPageAdapter(val memo: Memo) : ListAdapter<Page, InfinityPageAdapter.ViewHolder>(PageDiffCallback()) {
class ViewHolder(pageView: View) : RecyclerView.ViewHolder(pageView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InfinityPageAdapter.ViewHolder {
val pageView = LayoutInflater.from(parent.context).inflate(R.layout.infinity_page_list_item, parent, false)
return ViewHolder(pageView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val page = getItem(position)
val imageUrl = getMemoPath(memo.uuid) page.uuid ".webp"
if (imageUrl.isNotEmpty()) {
Glide.with(holder.itemView.context)
.load(imageUrl)
.apply(RequestOptions()
.signature(ObjectKey(System.currentTimeMillis()))
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.override(memo.pageWidth,memo.pageHeight)
)
.transition(DrawableTransitionOptions.withCrossFade())
.into(holder.itemView.findViewById(R.id.memo_page_image))
}
}
Есть ли способ уведомить recyclerview о том, что изображение изменилось, и принудительно перезагрузить изображение?
Я использую DiffUtil на адаптере. Насколько я понимаю, мне не нужно использовать notifyDataSetChanged(), когда вы используете DiffUtil. Но я не понимаю, как вы уведомляете об изменении изображения.
Я не знаю, является ли проблема с обратным вызовом Diff. Для чего это стоит, вот оно. Он не просматривает сам файл изображения, только имя файла изображения. Возможно, из-за того, что имя не меняется, изображение не обновляется. Но я не хочу менять имя файла при каждом редактировании.
class PageDiffCallback : DiffUtil.ItemCallback<Page>() {
override fun areItemsTheSame(oldItem: Page, newItem: Page): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Page, newItem: Page): Boolean {
return oldItem == newItem
}
}
Спасибо!
Джон
Ответ №1:
Дело в том, что вы обновляете не весь элемент в своем представлении recycler, а строку. notifyDataSetChanged() принудительно обновит данные, как вы сказали, но в этом случае он также обновит ваш макет.
С помощью DiffUtil, помимо содержимого, вы также сравниваете, совпадают ли элементы, которые они есть, поскольку вы сравниваете их идентификатор, и он не меняется при обновлении вашего изображения.
Прежде чем пытаться использовать notifyDataSetChanged(), не могли бы вы попробовать сделать это в своем areContentsTheSame()
методе:
override fun areContentsTheSame(oldItem: Page, newItem: Page): Boolean {
return oldItem.id == newItem.id amp;amp; oldItem.image == newItem.image // If you want just add more validations here
}
Комментарии:
1. Я попытался добавить поле метки
lastUpdated
времени к данным и изменил значениеareContentsTheSame
difference на readreturn oldItem.id == newItem.id amp;amp; oldItem.lastUpdated == newItem.lastUpdated
, но, похоже, оно по-прежнему не запускает обновлениеonBindViewHolder
, в котором я ожидаю увидеть действие. Вместо того, чтобы использоватьnotifyDataSetChanged()
I’m usingsubmitList()
, который запускает обратный вызов different , но, что интересно, временная метка в oldItem совпадает с временной меткой в newItem, что может быть причиной того, что представление не перерабатывается, а onBindViewHolder не вызывается.