NotifyDataSetChanged не работает, когда я читаю из sqlite

Когда я пытаюсь читать из SQLite и использую adapter.NotifyDataSetChanged. Я не вижу никаких изменений в моем recyclerView. Основная идея заключается в поиске в SQLite, где имя содержит значение из textView. Затем снова заполнить мой адаптер.

Я создаю экземпляр

 private List<InventoryPreviewClass> mItems;
 private RecyclerView mRecyclerView;
 adpInventoryPreview adapter;

Затем внутри метода onCreate()

mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID  = " + CategoryID + ""); //Here i am reading from sqlite

mRecyclerView.HasFixedSize = true;
var layout = new GridLayoutManager(this, InventoryRowsPerLine, GridLayoutManager.Vertical, false);
mRecyclerView.SetLayoutManager(layout);
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);

Пока код работает. Мой recyclerView заполнен моими элементами из sqlite.

Вот метод, когда пользователь вводит что-то в TextView

private void EtSearchAlwaysOn_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{      
   mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where  InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
   adapter.NotifyDataSetChanged();
}

Когда я что-то печатаю, в моем recyclerView ничего не меняется. Почему это происходит?

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

mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where  InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);

Почему это происходит? Я не думаю, что второй метод является правильным.

1-й: передайте mItems мимо ref 2-й: вместо того, чтобы пытаться сбросить весь адаптер, реализуйте подкласс Filter (developer.android.com/reference/android/widget/Фильтр) и используйте его в своем RecyclerView.Adapter, чтобы позволить отфильтрованному набору mitems динамически обновлять ваш RecyclerView, чтобы предотвратить «мигание» пользовательского интерфейса. " (постоянная очистка всего представления при каждом нажатии клавиши пользователем, которое обновляет запрос sql). 3-й: Просмотрите мой ответ здесь о том, как делать выборочные уведомления: stackoverflow.com/a/50692948/4984832

SushiHangover 08.04.2019 17:06
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
92
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Это происходит потому, что вы назначаете новый объект mItems

В первый раз, когда вы создаете список mItems, вы передаете его своему адаптеру, когда в следующий раз, когда вы получаете ответ от своей базы данных SQLite, создается новый экземпляр списка, поскольку вы назначаете его объекту.

Что вам нужно сделать, это

  • Создайте метод в адаптере, который принимает ваши элементы, такие как adapter.updateItems(newItems)
  • Метод должен очистить список, например items.clear(), а затем добавить новые элементы, которые вы передали с помощью items.addAll(newItems)
  • После этого вы можете вызвать notifyDataSetChanged() внутри самого адаптера, и он заработает.

В вашем адаптере это будет выглядеть так

public void updateItems(final List<InventoryPreviewClass> newItems) {
   items.clear();
   items.addAll(newItems);
   notifyDataSetChanged();
}

и тогда вы можете назвать это так

updatedList = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID  = " + CategoryID + "");

adapter.updateItems(updatedList);

Я думаю, вы упустили момент, что это типичный случай передачи по значению, а не по ссылке.

Да, это кажется лучшим подходом. Спасибо @droidchef

Prafulla Nayak 08.04.2019 17:18

Уведомить адаптер после установки адаптера.

mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");

adapter = new adpInventoryPreview(mItems);

mRecyclerView.SetAdapter(adapter);

adapter.notifyDataSetChanged();

Ваш ответ работает! Нужно ли утилизировать адаптер перед созданием нового, чтобы избежать утечек памяти?

DmO 08.04.2019 17:00

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

droidchef 08.04.2019 17:06

Каков наилучший подход для достижения этого @droidchef

Prafulla Nayak 08.04.2019 17:12

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

droidchef 08.04.2019 17:14

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

private List<InventoryPreviewClass> mItems;
  .
  .
  .
  public void setItems(List<InventoryPreviewClass> items)
   {
    mItems=items;
   }

а затем обновите свой метод поиска следующим образом

private void EtSearchAlwaysOn_TextChanged(object sender, 
 Android.Text.TextChangedEventArgs e)
 {      
 mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass 
 where  InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
 adapter.setItems(mItems);
 adapter.NotifyDataSetChanged();
 }
Ответ принят как подходящий

Это проблема byRef. Вы передаете указатель памяти 1 на свой адаптер и говорите ему следить за изменениями.

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

У вас есть два варианта.

  • Измените исходный список, сравнив новые результаты со старыми результатами, удалив и добавив по мере необходимости.
  • или Сообщите адаптеру, что у него есть новый указатель памяти, который он отслеживает, изменив элементы внутри адаптера. Создание метода для swapItems(items) будет работать. Затем вызовите notifyDataSetChanged внутри адаптера.

Спасибо, Сэм. Я предпочитаю метод 2. Мне он кажется более гибким. Нужно ли утилизировать адаптер перед этим? Сообщить каким-то образом, что предыдущей точки в памяти больше не существует? Чтобы избежать утечек памяти?

DmO 08.04.2019 17:06

хороший вопрос. Я никогда не беспокоюсь о старом списке, поскольку, когда вы перенаправляете его в новое место, сборщик мусора должен выполнять свою работу.

Sam 08.04.2019 17:08

@ Сэм, я думаю, он говорит об утилизации адаптера. Dmo вы не должны утилизировать, адаптер вообще в этом случае, потому что тогда вы потеряете на кеше viewholder, который создает ваш адаптер.

droidchef 08.04.2019 17:11

ой извините, не уловил. Нет, вам не нужно утилизировать адаптер. Спасибо дроидшеф. Я думал, ты спрашиваешь о старом списке.

Sam 08.04.2019 17:12

Другие вопросы по теме