У меня есть, ListView
который отображает новости. Они содержат изображение, заголовок и текст. Изображение загружается в отдельном потоке (с очередью и всем остальным), и когда изображение загружается, я вызываю notifyDataSetChanged()
адаптер списка, чтобы обновить изображение. Это работает, но getView()
вызывается слишком часто, так как notifyDataSetChanged()
вызывает getView()
все видимые элементы. Я хочу обновить только один элемент в списке. Как бы я это сделал?
Проблемы, которые у меня возникают с моим текущим подходом:
- Прокрутка медленная
- У меня есть плавная анимация на изображении, которая происходит каждый раз, когда загружается одно новое изображение в списке.
Этот вопрос задавали на Google I / O 2010, вы можете посмотреть его здесь:
Мир ListView, время 52:30
В основном то, что объясняет Ромен Гай, - это вызов
getChildAt(int)
методаListView
для получения представления и (я думаю) вызовgetFirstVisiblePosition()
для выяснения корреляции между позицией и индексом.Ромен также указывает на проект под названием Shelves в качестве примера, я думаю, он мог иметь в виду метод
ShelvesActivity.updateBookCovers()
, но я не могу найти вызовgetFirstVisiblePosition()
.УДИВИТЕЛЬНЫЕ ОБНОВЛЕНИЯ ГОРЯТ:
RecyclerView исправит это в ближайшем будущем. Как указано на http://www.grokkingandroid.com/first-glance-androids-recyclerview/ , вы сможете вызывать методы, чтобы точно указать изменение, например:
Кроме того, все захотят использовать новые представления на основе RecyclerView, потому что они будут вознаграждены красивой анимацией! Будущее выглядит потрясающе! :-)
источник
Вот как я это сделал:
У ваших элементов (строк) должны быть уникальные идентификаторы, чтобы вы могли обновить их позже. Установите тег для каждого представления, когда список получает представление от адаптера. (Вы также можете использовать ключевой тег, если тег по умолчанию используется где-то еще)
Для обновления проверьте каждый элемент списка, если представление с заданным идентификатором есть, оно видно, поэтому мы выполняем обновление.
На самом деле это проще, чем другие методы, и лучше, когда вы имеете дело с идентификаторами, а не позициями! Также вы должны вызвать обновление для элементов, которые становятся видимыми.
источник
сначала получить класс модели как глобальный, как этот объект класса модели
и инициализировать его глобальным
получить текущую строку представления по модели, инициализировав ее глобальной моделью
установите измененное значение в метод объекта глобальной модели, который будет установлен, и добавьте notifyDataSetChanged, чтобы он работал для меня
Вот связанный с этим вопрос с хорошими ответами.
источник
Ответы ясные и правильные, я добавлю
CursorAdapter
сюда идею для случая.Если Youre подклассов
CursorAdapter
(илиResourceCursorAdapter
, илиSimpleCursorAdapter
), то вы получите либо реализоватьViewBinder
или переопределенияbindView()
иnewView()
методы, они не получают текущий индекс элемента списка в качестве аргументов. Поэтому, когда поступают некоторые данные и вы хотите обновить соответствующие видимые элементы списка, как узнать их индексы?Мое обходное решение заключалось в следующем:
newView()
notifyDatasetChanged()
и обновлять их всеИз-за повторного использования представлений количество ссылок на представления, которые мне нужно хранить и повторять, будет примерно равно количеству элементов списка, видимых на экране.
источник
Для RecycleView используйте этот код
источник
Я использовал код, предоставленный Эриком, отлично работает, но у меня есть сложный пользовательский адаптер для моего списка, и я столкнулся с двойной реализацией кода, обновляющего пользовательский интерфейс. Я попытался получить новое представление из метода getView моих адаптеров (arrayylist, содержащий данные listview, уже обновлен / изменен):
Он работает хорошо, но я не знаю, хорошая ли это практика. Поэтому мне не нужно реализовывать код, который обновляет элемент списка два раза.
источник
именно я использовал это
источник
Я придумал другое решение, например, метод RecyclyerView void
notifyItemChanged(int position)
, создайте класс CustomBaseAdapter вот так:Не забудьте также создать класс CustomDataSetObservable для
mDataSetObservable
переменной в CustomAdapterClass , например:в классе CustomBaseAdapter есть метод
notifyItemChanged(int position)
, и вы можете вызвать этот метод, когда хотите обновить строку в любом месте (при нажатии кнопки или в любом месте, где вы хотите вызвать этот метод). И вуаля !, ваша единственная строка обновится мгновенно ..источник
Мое решение: если это правильно *, обновите данные и просматриваемые элементы, не перерисовывая весь список. Иначе notifyDataSetChanged.
Правильно - oldData size == новый размер данных, а старые идентификаторы данных и их порядок == новые идентификаторы данных и порядок
Как:
и конечно:
Игнорируйте последний параметр для bindView (я использую его, чтобы определить, нужно ли повторно использовать растровые изображения для ImageDrawable).
Как упоминалось выше, общее количество «видимых» просмотров - это примерно то количество, которое умещается на экране (без учета изменений ориентации и т. Д.), Так что с точки зрения памяти это не так уж важно.
источник
В дополнение к этому решению ( https://stackoverflow.com/a/3727813/5218712 ) просто хочу добавить, что оно должно работать, только если
listView.getChildCount() == yourDataList.size();
внутри ListView может быть дополнительный вид.Пример заполнения дочерних элементов:
источник