- The Developer World Is Yours
- The best place for Magento & Android tips and tricks… and much more!
- notifyDataSetChanged() – Android Example [Updated]
- notifyDataSetChanged() example:
- How to implement notifyDataSetChanged
- Android. Как работает метод notifyDataSetChanged () и ListViews?
- ArrayAdapter
- Создание адаптера
- Используем ресурсы
- Динамическое наполнение
- ListAdapter
- SpinnerAdapter
- Переопределяем адаптер
- Несколько советов
- Андроид. Как работает метод notifyDataSetChanged () и ListViews?
- 4 ответов
The Developer World Is Yours
The best place for Magento & Android tips and tricks… and much more!
notifyDataSetChanged() – Android Example [Updated]
notifyDataSetChanged() example:
This android function notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
You can use notifyDataSetChanged ArrayAdapter, but it only works if you use the add(), insert(), remove(), and clear() on the Adapter.
When an ArrayAdapter or BaseAdapter are constructed, it holds the reference for the List that was passed in. If you were to pass in a List that was a member of an Activity, and change that Activity member later, the ArrayAdapter is still holding a reference to the original List. The Adapter does not know you changed the List in the Activity.
How to implement notifyDataSetChanged
Your choices are:
Use the functions of the ArrayAdapter to modify the underlying List (add(), insert(), remove(), clear(), etc.)
Re-create the ArrayAdapter with the new List data. (Uses a lot of resources and garbage collection.)
Create your own class derived from BaseAdapter and ListAdapter that allows changing of the underlying List data structure.
Use the notifyDataSetChanged() every time the list is updated. To call it on the UI-Thread, use the runOnUiThread() of Activity. Then, notifyDataSetChanged() will work.
Multiple choice in listView
You need:
Interface
Data (String text, boolean selected)
Adapter
Fragment or Activity (calling notifyDataSetChanged custom adapter)
list_item.xml
You can start with data:
In your fragment or activity:
You can download the source code of this example in github.
If you have any questions about the usage of notifyDataSetChanged leave a comment below and we’ll try to help you.
Источник
Android. Как работает метод notifyDataSetChanged () и ListViews?
Я пытаюсь понять концепцию ListView и как она работает, и я пытаюсь создать собственный адаптер, который расширяет BaseAdapter . Например, для ArrayAdapter существует метод notifyDataSetChanged() который следует вызывать после обновления списка массивов, который содержит все ваши данные, чтобы обновить ListView .
Но я создаю свой собственный подкласс BaseAdapter . Этот метод недоступен мне, или он? Как реализовать этот метод? В принципе, что делает этот метод точно, может быть, я пойму тогда.
В случае ArrayAdapter я предполагаю, что он смотрит, в какой позиции ListView отображается в настоящее время, и проверяет, совпадает ли он с ArrayList после его обновления? Или…
В нем говорится, что метод:
Сообщает заинтересованным наблюдателям, что базовые данные были изменены, и любой вид, отражающий набор данных, должен обновиться.
Но как именно он обновляется?
Может ли кто-нибудь объяснить, пожалуйста?
Я понял это . Я не мог понять, как, черт возьми, появился адаптер и как он узнал, откуда взять данные. Когда я расширил класс BaseAdapter , в конструкторе этого класса я инициализировал список элементов, которые я хотел увидеть в ListView . Но я не мог понять, как эти ценности будут использоваться и когда.
Вот и все! :
В BaseAdapter есть некоторые методы, которые необходимо переопределить. Среди них есть getCount() .
Когда ListView создан и еще много чего, он вызывает getCount() . Если это возвращает значение, отличное от 0 (я вернул размер ArrayList, который я ранее инициализировал в конструкторе), то он вызывает getView() достаточно времени, чтобы заполнить экран элементами. Например , я инициализировал ArrayList с 20 элементами. Поскольку только 8 элементов первоначально поместились на экране, getView() был вызван 8 раз, каждый раз прося позицию, которую мне нужно было вернуть (точнее, он хотел знать, как строка будет выглядеть в списке на этой конкретной позиции , Какие данные он должен содержать). Если я getView() список вниз, getView() будет вызываться снова и снова, «пока я не getView() в конец списка, в моем случае 20 элементов / строк.
Что notifyDataSetChanged() делает … когда он вызывается, он смотрит, какие элементы отображаются на экране в момент его вызова (точнее, какие индексы строк) и вызывает getView() с этими позициями.
Т.е. если вы показываете первые 8 элементов в списке (так это те, которые видны на экране), и вы добавляете другой элемент между вторым и третьим элементами в списке, и вы вызываете notifyDataSetChanged() тогда getView() 8 раз, с позициями, начинающимися с 0 и заканчивающимися на 7, и потому что в getView() вы получаете данные из ArrayList тогда он автоматически возвращает новый элемент, вставленный в список, рядом с 7 из предыдущих 8 (7 А не 8, потому что последний элемент ушел на одну позицию вниз, поэтому он больше не виден), и ListView будет перерисовывать или что-то еще с этими элементами.
Также важно указать, что если вы правильно реализовали getView() , вы в конечном итоге переработаете объекты (объекты), которые уже были показаны (вместо создания новых). Посмотрите это видео около 12:00 минут, чтобы увидеть правильный способ реализации getView()
Я понял все это, поместив вызовы в LogCat во всех методах и после того, что происходило.
Надеюсь, это поможет кому-то, кто только начинает понимать, как работает ListView .
PS Этот пример также помог мне понять.
BaseAdapter можно «наблюдать» другими классами. Когда вы вызываете метод ListView setAdapter() это вызовы registerDataSetObserver адаптера. Итак, адаптер знает, кто интересуется новыми данными.
Здесь вы можете проверить источник BaseAdapter . Это довольно мало.
notifyDataSetChanged доступен для вас, и вы не должны его переопределять (потому что он не делает ничего особенного, поэтому вы можете просто повторно использовать его в своем классе).
Предположим, что ваш ListView отображает некоторые данные, хранящиеся в ArrayList .
После того, как вы измените содержимое ArrayList , вам нужно сообщить списку, что источник данных был изменен, и ему нужно перерисовать его, чтобы показать новые данные.
Таким образом, здесь notifyDatasetChanged() . Он сообщает ListView что данные были изменены; И чтобы показать новые данные, ListView должен быть перерисован.
Поскольку вы расширяете BaseAdapter самостоятельно для создания подкласса, вы также получите notifyDataSetChanged() .
Источник
ArrayAdapter
Создание адаптера
ArrayAdapter является простейшим адаптером, который специально предназначен для работы с элементами списка типа ListView, Spinner, GridView и им подобным. Создать адаптер этого вида можно так:
В параметрах используется контекст, XML-разметка для отдельного элемента списка и массив данных. Контекстом может быть сама активность (this), под разметкой подразумевается компонент, в котором выводится текст, например, TextView, а данными является подготовленный массив, все элементы которого по очереди вставляются в указанную разметку.
Разметку можно создать самостоятельно, а можно использовать готовую системную разметку. Если посмотреть на исходники файла simple_list_item_1.xml в документации Android SDK, то увидим, что он содержит TextView. В этом коде мы создали адаптер ArrayAdapter, в котором данные элемента TextView представлены в виде строк.
Чтобы код был более читаемым, можно сделать ещё так:
Мы вынесли массив строк в отдельную переменную.
Используем ресурсы
Если у нас есть готовый файл ресурсов (массив строк), то можно использовать специальный метод createFromResource(), который может создать ArrayAdapter из ресурсов:
Подготовим массив строк:
Теперь мы можем воспользоваться адаптером и применить к Spinner:
В этом примере мы использовали системную разметку android.R.layout.simple_spinner_item, которая тоже содержит TextView.
При использовании этого метода вы можете применять локализованные версии, что очень удобно.
Или можно пойти другим путём. Получить массив из ресурсов и вставить его в адаптер, как в самом первом примере.
Динамическое наполнение
Также мы можем создать массив программно.
ListAdapter
ListAdapter является интерфейсом. По сути ничего не меняется. Заменяем ArrayAdapter adapter на ListAdapter adapter и получаем тот же результат.
Данный интерфейс может пригодиться при создании собственного адаптера, а для стандартных случаев выгоды не вижу.
SpinnerAdapter
SpinnerAdapter также является интерфейсом и может использоваться при создании собственных адаптеров на основе ArrayAdapter. В стандартных ситуациях смысла использования его нет. Вот так будет выглядеть код:
Переопределяем адаптер
По умолчанию ArrayAdapter использует метод toString() из объекта массива, чтобы наполнять данными элемент TextView, размещённый внутри указанной разметки. Если вы используете ArrayAdapter , где в параметре используется ваш собственный класс, а не String, то можно переопределить метод toString() в вашем классе. Пример такого решения есть в конце статьи Android: Простейшая база данных. Часть вторая.
Другой способ. Мы хотим выводить данные не в одно текстовое поле, а в два. Стандартная разметка для списка с одним TextView нам не подойдёт. Придётся самостоятельно создавать нужную разметку и наполнять её данными.
В этому случае нужно наследоваться от класса ArrayAdapter, указывая конкретный тип и переопределяя метод getView(), в котором указать, какие данные должны вставляться в новой разметке.
Метод getView() принимает следующие параметры: позицию элемента, в котором будет выводиться информация, компонент для отображения данных (или null), а также родительский объект ViewGroup, в котором указанный компонент поместится. Вызов метода getItem() вернёт значение из исходного массива по указанному индексу. В результате метод getView() должен вернуть экземпляр компонента, наполненный данными.
Допустим, у нас есть простой класс Cat с двумя полями — имя и пол. Нашему списку понадобится специальная разметка, состоящая из двух текстовых полей. Создадим адаптер, который будет использовать класс Cat вместо String и будем извлекать данные из объекта класса.
Как видите, достаточно просто изменить программу, используя свой класс вместо String.
В методе getView() используется не совсем корректная версия метода inflate(). Подробнее об этом читайте в статье LayoutInflater
Класс ArrayAdapter позволяет динамически изменять данные. Метод add() добавляет в конец массива новое значение. Метод insert() добавляет новое значение в указанную позицию массива. Метод remove() удаляет объект из массива. Метод clear() очистит адаптер. Метод sort() сортирует массив. После него нужно вызвать метод notifyDataSetChanged.
Несколько советов
ArrayAdapter имеет шесть конструкторов.
- ArrayAdapter(Context context, int resource)
- ArrayAdapter(Context context, int resource, int textViewResourceId)
- ArrayAdapter(Context context, int resource, T[] objects)
- ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)
- ArrayAdapter(Context context, int resource, List objects)
- ArrayAdapter(Context context, int resource, int textViewResourceId, List objects)
У них у всех первые два параметра — это контекст и идентификатор ресурса для разметки. Если корневой элемент разметки является контейнером вместо TextView, то используйте параметр textViewResourceId, чтобы подсказать методу getView(), какой компонент используется для вывода текста.
Сам адаптер работает с данными, как со списками. Если вы используете стандартный массив, то адаптер переконвертирует его в список. Сами данные необязательно сразу передавать адаптеру, можно сделать это позже через метод addAll().
Другие полезные методы адаптера:
- add() — добавляет объект в коллекцию
- remove() — удаляет объект из коллекции
- getItem(int position) — возвращает объект из позиции position
- getContext() — получает контекст
На последний метод следует обратить внимание при создании собственного адаптер на основе ArrayAdapter. Не нужно в своём классе объявлять контекст таким образом.
Через метод getContext() вы уже можете получить доступ к контексту, не объявляя новой переменной.
Тоже самое применимо и к массивам. Не нужно объявлять массив:
Используйте метод getItem(position), который может получить доступ к массиву.
Если позволяет логика, используйте списки вместо массивов для большей гибкости. Тогда вы можете добавлять и удалять данные через методы add() и remove().
Источник
Андроид. Как работает метод notifyDataSetChanged () и ListViews?
Я пытаюсь понять ListView концепция и как она работает, и я пытаюсь создать свой собственный адаптер, который расширяет BaseAdapter . Для ArrayAdapter например, есть notifyDataSetChanged() метод, который должен быть вызван после обновления списка массивов, который содержит все ваши данные, чтобы обновить ListView .
но я создаю свой собственный подкласс BaseAdapter . Этот метод мне недоступен или нет? Как реализовать этот метод? В принципе, что делает этот метод вот именно, может быть, тогда я пойму.
в случае ArrayAdapter Я предполагаю, что он смотрит на какую позицию ListView в настоящее время отображается, и он проверяет, является ли он таким же, как в ArrayList после того, как он был обновлен? Или.
в нем говорится, что метод:
уведомляет прикрепленных наблюдателей о том, что базовые данные изменено, и любое представление, отражающее набор данных, должно обновиться.
но как именно это происходит обновить себя?
может кто-нибудь объяснить, пожалуйста?
4 ответов
я понял. Я не мог понять, как, черт возьми, начался адаптер и как он узнал, откуда получить данные. Когда я расширил BaseAdapter класс, в конструкторе этого класса я инициализировал список элементов, которые я хотел видеть в ListView . Но я не мог понять, как эти значения будут использоваться и когда.
так вот в чем дело . :
на BaseAdapter есть некоторые методы, которые должны быть переопределенный. Среди них есть getCount() .
когда ListView создается и еще много чего, он вызывает getCount() . Если это возвращает значение, отличное от 0 (я вернул размер ArrayList, который я ранее инициализировал в конструкторе), то он вызывает getView() достаточное количество раз, чтобы заполнить экран с элементами. например, я инициализировал ArrayList С 20 пунктов. Потому что только 8 предметов изначально помещаются на экране, getView() был вызван 8 раз, каждый раз спрашивая позиция, которую мне нужно было вернуть (точнее, он хотел знать, как строка будет выглядеть в списке на этой конкретной позиции, какие данные она должна содержать). Если прокрутить список вниз, getView() вызывается снова и снова, пока я не достигну конца списка, в моем случае 20 элементов / строк.
что notifyDataSetChanged() делает . при вызове он смотрит, какие элементы отображаются на экране в момент его вызова (точнее, какие индексы строк ) и вызывает getView() с этими позициями.
то есть если вы отображаете первые 8 элементов в списке (так что это те, которые видны на экране), и вы добавляете другой элемент между 2-м и 3-м элементом в списке, и вы вызываете notifyDataSetChanged() затем getView() вызывается 8 раз, причем позиции начинаются с 0 и заканчиваются на 7, а потому в getView() метод вы получаете данные из ArrayList затем он автоматически вернет новый элемент, вставленный в список вместе с 7 из предыдущий 8 (7, а не 8, потому что последний элемент пошел на одну позицию вниз, поэтому он больше не виден), и ListView будет перерисовываться или что-то еще с этими элементами.
кроме того, важно указать, что если вы используете getView() правильно, вы закончите переработку элементов (объектов), уже отображаемых (вместо создания новых). См.видео около 12: 00 минут, чтобы увидеть правильный способ реализации getView()
я понял все это, сделав звонки в LogCat в каждом методе и после того, что происходило.
надеюсь, это поможет кому-то, кто только сейчас начинает понимать, как ListView s работа.
П. С. также помогли мне многое понять.
BaseAdapter может «наблюдаться» другими классами. Когда вы вызываете метод ListView это registerDataSetObserver адаптер. Таким образом, адаптер знает, кто заинтересован в новых данных.
вы можете проверить источник BaseAdapter здесь. Он довольно маленький.
notifyDataSetChanged is доступно для вас, и вы в основном не должны переопределять его (потому что он не делает ничего особенного, поэтому вы можете просто использовать его в своем собственном классе).
Предположим ваш ListView отображает некоторые данные, хранящиеся в ArrayList .
после изменения содержание ArrayList , вам нужно сообщить списку, что источник данных изменился, и ему нужно перерисовать себя, чтобы показать новые данные.
вот здесь notifyDatasetChanged() приходит. Он говорит ListView , что данные были изменены; и чтобы показать новые данные, ListView должно быть переписано.
Как вы расширяете BaseAdapter для вашего собственного для создания подкласса вы получите notifyDataSetChanged() способ также.
Источник