Android adapter удалить элемент

Полный список

— используем SimpleAdapter для построения списка
— добавляем и удаляем записи в списке

Как выводить данные в список с помощью SimpleAdapter мы знаем. Теперь попробуем эти данные менять. Сделаем список с возможностью удаления и добавления записей. Добавлять будем кнопкой, а удалять с помощью контекстного меню.

Project name: P0511_SimpleAdapterData
Build Target: Android 2.3.3
Application name: SimpleAdapterData
Package name: ru.startandroid.develop.p0511simpleadapterdata
Create Activity: MainActivity

Кнопка для добавления и список. Из интересного можно отметить свойство onClick у кнопки. Дальше станет понятно, что это.

Layout для пункта списка item.xml:

Картинка и текст.

В методе onCreate мы формируем коллекцию Map-объектов, массивы сопоставления, создаем адаптер и список, добавляем возможность контекстного меню для списка.

Метод onButtonClick – его мы указали в main.xml в свойстве onClick кнопки. И теперь при нажатии на кнопку выполнится этот метод. Отдельный обработчик нажатия не нужен.

В этом методе мы создаем новый Map, добавляем его к коллекции данных и сообщаем, что данные изменились и надо обновить список.

Метод onCreateContextMenu – создание контекстного меню. Создаем только один пункт — для удаления записи.

В onContextItemSelected обрабатываем нажатие на пункт контекстного меню. При вызове контекстного меню объект, для которого оно было вызвано, передает в меню информацию о себе. Чтобы получить данные по пункту списка, для которого был совершен вызов контекстного меню, мы используем метод getMenuInfo. Объект AdapterContextMenuInfo содержит данные о View, id и позиции пункта списка. Мы используем позицию для удаления соответствующего Map из коллекции. После этого сообщаем, что данные изменились.

Все сохраним и запустим.

На скрине показано контекстное меню, которое вызывается при долгом нажатии на пункт списка. За ним виден список и кнопка для добавления записей.

Записи добавляются и удаляются. Редактирование я не стал делать. Там принцип тот же. Получаете Map и меняете его атрибуты.

Из кода видно, что для обновления списка надо поменять данные, которые использует адаптер, и вызвать его метод-уведомление.

На следующем уроке:

— используем SimpleCursorAdapter для построения списка
— добавляем и удаляем записи в списке

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Android RecyclerView добавление и удаление элементов

У меня есть RecyclerView с текстовым полем TextView и кросс-кнопка ImageView. У меня есть кнопка за пределами окна просмотра, которая делает видимую / исчезнувшую перекрестную кнопку ImageView.

Я ищу, чтобы удалить элемент из recylerview, когда эти элементы крест кнопка ImageView нажата.

Как я могу получить что-то вроде onClick, работающее для моего CrossButton ImageView? Есть ли способ лучше? Может быть, изменив весь элемент на клик, чтобы удалить элемент? В окне повторного просмотра отображается список мест, которые необходимо отредактировать. Любые технические советы или комментарии / предложения по наилучшей реализации будут высоко оценены.

Я сделал что-то подобное. В вашем MyAdapter :

Надеюсь это поможет.

Редактировать:

getPosition() устарела, используйте getAdapterPosition() вместо этого.

Прежде всего, элемент должен быть удален из списка!

если этот предмет не удален, используйте этот магический метод 🙂

проблема

RecyclerView по умолчанию не знает изменений вашего набора данных. Это означает, что всякий раз, когда вы делаете удаление / добавление в свой список данных, эти изменения не будут отражены непосредственно в вашем RecyclerView.

Решение

RecyclerView предлагает вам несколько способов поделиться своим состоянием набора данных. Это происходит потому, что изменение вашего набора данных не подразумевает изменения представления, и наоборот. Стандартные API-интерфейсы Android позволяют связать процесс удаления данных (для целей вопроса) с процессом удаления представлений.

Лучший подход

Если вы не укажете правильно, что происходит при добавлении / удалении элементов (речь идет о представлениях), дети RecyclerView анимируются без ответа из-за отсутствия информации о том, как перемещать различные представления по списку.

Вместо этого следующий код будет точно воспроизводить анимацию только на IndexOutOfBoundException удаленном дочернем элементе (и, как примечание, для меня он исправил любые s, помеченные стековой трассировкой как «несогласованность данных»)

Читайте также:  Android sdk running on device

Если заглянуть внутрь, RecyclerView мы можем найти документацию, объясняющую, что вторым параметром, который мы должны передать, является количество элементов, которые удаляются из набора данных, а не общее количество элементов (как неправильно указано в некоторых других источниках информации).

Источник

Android RecyclerView добавление и удаление элементов

У меня есть RecyclerView с текстовым полем TextView и перекрестной кнопкой ImageView. У меня есть кнопка вне recyclerview, которая делает перекрестную кнопку ImageView видимой / исчезнувшей.

Я ищу, чтобы удалить элемент из recylerview, когда нажата кнопка пересечения элементов ImageView.

Как я могу получить что-то вроде onClick, работающего для моего crossButton ImageView? Есть лучший способ? Может быть, изменение всего элемента onclick в удаление элемента? Recyclerview показывает список местоположений, которые необходимо отредактировать. Любые технические советы или замечания / предложения по наилучшей реализации будут чрезвычайно признательны.

12 ответов

Я сделал что-то подобное. В MyAdapter :

надеюсь, что это помогает.

Edit:

getPosition() это depricated теперь использовать .

во-первых, элемент должен быть удален из списка!

если все еще элемент не удален используйте этот магический метод:)

Я пробовал все вышеперечисленные ответы, но вставка или удаление элементов в recyclerview вызывает проблему с позицией в наборе данных. В конечном итоге с помощью delete(getAdapterPosition()); внутри viewHolder, который отлично работал при поиске положения элементов.

на самом деле с ранее упомянутым кодом (который вы можете найти здесь ниже) все чайлды RecyclerView анимируются, когда один элемент удаляется, и это вообще не отзывчивое решение, также потому, что у него есть некоторые потенциальные скрытые проблемы

вместо этого следующий фрагмент будет воспроизводить анимацию только на удаляемом ребенке, и с моей стороны он перестал бросать IndexOutOfBoundException s, помеченные отладчиком как «несоответствие данных»

если мы копайте в RecyclerView класс мы можем найти pice javadoc, который имеет объяснение, действительно, в качестве второго параметра мы должны передать количество элементов, которые удаляются из набора данных, а не общее количество элементов

проблема была в том, что я удалял элемент из списка, который больше не был связан с адаптером, чтобы убедиться, что вы изменяете правильный адаптер, вы можете реализовать такой метод в своем адаптере:

и вызовите его в своем фрагменте или деятельности, как это:

возможно, дубликат ответа, но довольно полезный для меня. Вы можете реализовать метод, приведенный ниже в RecyclerView.Adapter и может использовать этот метод в соответствии с вашими требованиями, я надеюсь, что это будет работать для вас

вот некоторые визуальные дополнительные примеры. См.мой более полный ответ для примеров добавления и удаления диапазона.

добавить один элемент

добавить «свинья» по индексу 2 .

удалить один элемент

удалить «свинья» из списка.

если вы хотите удалить пункт, вы должны сделать это: первое удаление:

на следующем шаге вы должны уведомить адаптер recycler, что вы удалите элемент с помощью этого кода:

но если вы измените пункт, сделать это: сначала измените параметр вашего объекта следующим образом:

затем сообщите своему адаптеру recycler, что вы изменяете элемент этим кодом:

надеюсь, что помогает вы.

сделать интерфейс в пользовательский класс адаптера и обработки нажмите событие на recycler view..

после определения адаптера и привязки к представлению recycler, называемому ниже кодом..

Источник

ziginsider

25 февраля 2017

Заметки о RecyclerView. Принципы работы. Внутреннее устройство.

Оглавление

Принцип работы RecyclerView в общих словах

Прокручивается список, создаются вьюхи и выводятся на экран, при этом выполняется onCreateViewHolder() и onBindViewHolder() .

Ушедшие за экран вьюхи не уничтожаются, а попадают в пул объектов Recycled Pool .

При дальнейшем скролле, вьюхи появляющиеся из-за пределов экрана не пересоздаются, а берутся из этого самого пула . При этом срабатывает только onBindViewHolder() .

Говоря отвлеченно, метод onCreateViewHolder() создает “бассейн”, а метод onBindViewHolder() “наполняет бассейн водой”. Если каждый раз, когда меняется представление (скролл) не “менять воду в бассейне” полностью т.е. не переопределять содержание всех элементов, которые могут измениться, в onBindViewHolder() , то вьюха может выдавать сюрпризы в виде старых значений.

Компоненты RecyclerView

  • LayoutManager — размещает элементы
  • ItemAnimator — анимирует элементы
  • Adapter — создает элементы
  • Decorator — дорисовывает элементы
  • ViewHolder — кеширует findViewById

LayoutManager

  • LinearLayoutManager (линейное размещение элементов)
  • GridLayoutManager (табличное)
  • StaggeredGridLayoutManager (сложное)


Обязаности LayoutManager’а:

  • размещает элементы
  • отвечает за размер элементов (measure)
  • отвечает за то, какие элементы больше не нужны
  • отвечает за скроллинг
  • отвечает за View Focusing (В случае ListView отвечал сам ListView ); т.е. на каком элементе сфокусироваться.
  • отвечает за Accessibility; для людей с ограниченными возможностями.
Читайте также:  Операционная система андроид информация

Что делать, если стандартная реализация не подходит? Два варианта:

  • Переопределить стандартный LayoutManager:
    Например, у нас есть LinearLayoutManager. Нам необходимо сделать так, что при малом количестве элементов, наш LinearManager будет по высоте занимать ровно столько места, сколько нужно под это количество элементов. Тогда делаем свой ExtendedLinearLayoutManager, где переопределяем метод onMeasure().
  • Написать свой LayoutManager:
    Достаточно переопределить (для компиляции) метод RecyclerView.LayoutParams generateDefaultLayoutParams(…), который будет говорить, какие по умолчанию параметры должны быть применены к новым View.
    Не стоит забывать также void onLayoutChildren(…) — непосредственное размещение наших дочерних View на экране.
    boolean canScrollHorizontally(…) — говорим можем ли мы листать горизонтально
    boolean canScrollVertically(…) — вертикально…

Adapter

Обязанности Adapter’а:

  • создание ViewHolder’ов
  • заполнение ViewHolder’ов информацией
  • уведомление RecyclerView о том какие элементы изменились.
  • обработка касаний
  • частичное обновление данных
  • управление количеством ViewType’ов
  • информация о переиспользовании ViewHolder’а

Основное API Adapter’a:

При изменении позиции элемента не вызывается, поэтому нельзя вызывать так: см. типичные ошибки #1

Методы notifyItemX

Нужны для того, чтобы изменять, удалять, добавлять элементы и при этом анимировать их:

польза от методов notifyItemX():

  • Нет лишних вызовов onBindViewHolder() ;
  • Возможность анимировать и перемещать элементы как угодно
  • Нет лишних вызовов onCreateViewHolder()
  • если в конструкторе вызвать этот метод с true, то RecyclerView сам будет вычислять, какие элементы поменялись местами, какие добавились, удалились и т.д. Для этого необходимо реализовать:

и давать уникальное Id элемента на основе его содержимого или создавать Id на основе Id layout’a, из которого мы надуваем это view, и который всегда уникальный.

ViewHolder

Обязателен, в отличии от реализации ListView. (NB: см. отличия RecyclerView от ListView в этой заметке)

Для чего нужен был ViewHolder раньше? Ответ: кеширование относительно дорогого findViewById

Для чего нужен ViewHolder теперь?

  • кеширование относительно дорогого findViewById
  • Мост между LayoutManager, Animator’ами и Decorator’ами
  • Основной элемент Recycling’а

NB: Как правильно организовать код, когда ViewHolder’ов несколько (несколько типов элементов в одном RecyclerView)? Ответ см. в этой заметке: Различные типы Item View в RecyclerView

Жизнь и смерть ViewHolder

  • LayoutManager дает запрос RecyclerView на элемент: getViewForPosition
  • RecyclerView обращается в Cache
  • Если в Cache нет элемента, RecyclerView идет в Adapter и просит у него viewType
  • Получив ViewType RecyclerView идет в Recycler Pool: getViewHolderByType, в котором может хранится элемент с неправильными данными, которые надо потом заполнить.
  • Если Recycler Pool не вернул элемент, он идет в Adapter и просит последнего создать элемент.
  • Если Recycler Pool вернул элемент, то RecyclerView просит Adapter сделать bindViewHolder (заполнить данные) и возвращает элемент LayoutManager’у

В случае, если LayoutManager добавляет элемент:

  • LayoutManager сообщает RecyclerView о том, что создает элемент: addView
  • RecyclerView посылает запрос Adapter’у: onViewAttachedToWindow

В случае удаления элемента:

  • LayoutManager сообщает RecyclerView о том, что удаляет элемент: removeAndRecycleView
  • RecyclerView посылает запрос Adapter’у: onViewDettachedToWindow
  • RecyclerView идет в Cache, если элемент валидный (isValid? А если не valid то сразу идет в Recycler Pool) для этой позиции, помещает туда элемент
  • Cache помещает старые элементы в Recycler Pool (recycle)
  • Recycled Pool сообщает Adapter’у, что элемент (view) был переиспользован и Adapter может сделать с ним что хочет: onViewRecycled (те элементы которые попадают в Recycled Pool, понадобятся нескоро, в отличии от тех, которые находятся в Cache)

Удаление из представления с т.з. RecyclerView:
RecyclerView при удалении своего child из представления (прокрутка, удаление элемента) view не удаляет ее сразу, но помещает в re add to ViewGroup, скрывает view от LayoutManager’а (иначе LM упадет с exeption, т.к. он занет только о видимых элементах) и говорит ItemAnimator’у, что ее надо анимировать.

Удаление из представления с т.з. LayoutManager’а:
Если LayoutManager удаляет элемент из представления он посылает запрос к RecyclerView removeAndRecycleView. RecyclerView проверяет view на валидность (isValid?) NO! -> отправляет view в Recycler Pool. Recycled Pool проверяет элемент на транзиентность hasTransientState? – состояние (на системном уровне, а не уровне RecyclerView) когда не ясно в каком состоянии view (например, анимация или selection text). И тут (hasTransientState = true) выходит на сцену Adapter. У него есть возможность последний раз сказать RecyclerView, что view можно переиспользовать. И если он скажет, что можно, то recycle’м его, иначе – навсегда его теряем (отсюда вывод: единственный, кто может анимировать view – ItemAnimator. Остальное на свой страх и риск: можно потерять ViewHolder)

NB: как проверить список на ошибки (торможнение, неправильное использование hasTransientState и глюки из-за этого). Открываем дебажный лог и начинаем прокручивать список. Если видим, что потребление памяти растет, то у нас ошибка в архитектуре Recycler’а (ViewHolder не освобождается)

Читайте также:  Android message what codes

Еще один способ умереть ViewHolder’у. RecyclerView обращается к Recycled Pool: addViewToPool. Recycled Pool проверяет есть ли место для еще одного ViewHolder’а типа Х. Если место есть, то ОК. Иначе, ViewHolder умирает.

Почему места может не быть?

  • Слишком много ViewHolder’ов одного типа Почему слишком много?
  • Произошла crossfade анимация для всего списка
  • notifyItemRangeChanged(0, getItemCount());
    Как исправить?
  • Правильно вызывать notifyItemChanged
  • pool.setMaxRecycledViews(type, count); (кол-во эл-ов кот. будут кэшиться, важно для тех у кого неоднородные списки, для одних типов (тех кот.больше на экране) можно увеличить значения, для других (тех кот. меньше) – уменьшить)

ItemDecoration

Adapter — для того чтобы представить какой-либо массив данных на экране. ItemDecoration — для того чтобы дополнить это представление в зависимости от какой-либо логики (например, смена ориентации экрана) вашего приложения.

Для чего применяется:

  • добавление разделителей и отступов
  • отображение выбранного элемента (выделение)
  • рисование любого контента за и перед view

onDraw() и onDrawOver() — вызываются на каждый шаг отрисовки списка, поэтому в этих методах не стоит помещать тяжелых операций (инициализация объекта и т.д.)

Декораторов у RecyclerView может быть не один, а несколько, что позволяет помещать различную логику в разные классы.

И для избегания таких ситуаций есть замечательные методы:

ItemTouchHelper

Статья призванная показать, как использовать ItemTouchHelper в RecyclerView: Drag and Swipe with RecyclerView

ItemAnimator

ItemAnimator — позволяет анимировать добавление, удаление, изменение элементов.

Схема запуска анимации после методов notifyItemX() (методы см. выше):

Отрисовка элементов делится на два этапа:

  • preLayout — элементы до изменения списка + те, что должны появиться;
  • postLayout — элементы после окончания анимации. RecyclerView запоминает состояние preLayout и сравнивает его с состоянием PostLayout. И определив эту разницу, RecyclerView запускает анимацию элементов.

ExpandableLayout

  • Подход 1 (неправильный): Дерграем requestLayout() для view:

Плохой подход т.к. requestLayout() не предназначен для анимации

  • Подход 2: Кастомный Adapter

RecyclerView и SQLite

На практике довольно часто данные для RecyclerView беруться из базы данных SQLite. Можно, конечно, сначала получать данные из базы данных (с помощью SQLiteCursor) и затем передавать их через конструктор RecyclerView для отображения. Но есть готовое решение:

CursorRecyclerViewAdapter — организует работу RecyclerAdapter поверх курсора. Т.е. вам нужно получить курсор, и без посредников, передать его в CursorRecyclerViewAdapter.

Paging Library — Решение от Google в рамках Android Architecture Components. В данном случае взаимодействует с Room

Типичные ошибки новичка

1) Обработка нажатий на элемент внутри onBindViewHolder(…):

Во-первых, создается объект на каждый Bind. Во-вторых, берется position элемента, которая у него была до onBindViewHolder() . Но элемент с помощью notify() может быть перемещен/удален и его position, следовательно, измениться. Для этой ситуации есть решение, а именно установить слушатель нажатия при создании элемента:

Очень важно проверить на NO_POSITION . Сложно представить, как можно кликнуть на то, у чего нет позиции, но иногда такое происходит. Рекомендация от Google не забывать делать эту проверку.

Но зачем кэшировать (создавать) заранее? Надо создавать, когда в этом есть необходимость.

Практика

Как заполнить RecyclerView данными, когда их много?

Повесьте на RecyclerView слушатель прокрутки и, когда он будет прокручен до последнего элемента (или до, скажем, середины списка, чтобы начать загрузку раньше, чем пользователь достигнет конца списка), подгружайте новую порцию данных.

В адаптере можно получить позицию только что появившегося элемента списка. Если позиция появившегося элемента последняя, значит пора подгружать новую порцию данных

Способ №3:

Для организации постепенной подгрузки можно использовать Pagging Library. Библиотека представлена вместе с Architecture Components (см. заметки по ним). Сам запуск механизма подгрузки аналогичен первым двум способам.

Использовать одну из готовых библиотек (например, BRVAH). Такой способ не всегда может подойти, так как приходится тянуть всю библиотеку в проект.

Как обновить данные в RecyclerView?

Ответ только один: обернуть RecyclerView в SwipeRefreshLayout. Теперь можно применять жест названный в народе “резинка от трусов” т.е. потянуть вниз RecyclerView, отпустить, появиться виджет загрузки и т.д.

К первым двум вопросам хочется добавить, что когда мы организуем загрузку данных из сети в приложении, обновляем их, подгружаем в список и т.д. — то очень важно продумать логику взаимодействия (ошибки соединения, если данных нет, если загружены уже все данные, если еще ничего не загружено и т.п.). Понять о чем идет речь, можно из этого доклада, где автор дает хитрое решение данной логики с помощью концепции конечных автоматов. Сам код смотреть здесь.

Как организовать код, когда имеем вложенные в друг друга RecyclerView?

Как организовать код, когда имеем разные типы View в RecyclerView?

Источник

Оцените статью