3

Есть БД с таблицей в которой около 50 тыс. записей. Необходимо их вывести в RecyclerView.

Скажите если я использую адаптер, который использует коллекцию для вывода данных в список не будет ли лагать приложение?

Т.е. адаптер будет получать коллекцию из элементов из БД и будет выводить в список.

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

Kolhoznik
  • 1,061
  • 15
  • 25
  • По идее логика правильная: записи из БД извлекаем и кладем в коллекцию (arraylist какой-нибудь) - коллекцию кидаем в адаптер ресайкла. А какая БД? – YaPV Dec 25 '17 at 10:07
  • Sqlite.. Просто мне интересно 50 тысяч записей в коллекцию класть и из коллекции в RecyclerView с точки зрения ресурсов нормально? или лучше другой подход – Kolhoznik Dec 25 '17 at 10:09
  • Если вы собираетесь доставать данные из БД, затем складывать их в коллекцию и из колекции выводить в список, то такое решение будет лагать на любом гаджете со 100% вероятностью. Решение дилетанское и очень плохое по многим параметрам. Есть общепринятое решение - выводить данные напрямую из Cursor в список обязательно через CursorLoader. Пример использования CursorLoader (здесь ListView но сути это никак не меняет) – pavlofff Dec 25 '17 at 11:41

1 Answers1

3

Будет "лагать" или нет зависит от нескольких факторов:

  1. Мощность гаджета
  2. Какой объем данных у вас в одной записи в базе данных. Скажем, если у вас хранятся комментарии пользователей из условного сайта, то размер записи в базе данных может быть довольно большой. Как следствие, 50 000 записей это большой объем данных.
  3. Как вы достаете данные из SQLite и кладете их коллекцию. Например, вы получаете данные из базы, но не напрямую их в коллекцию кладете, а перед этим формируете POJO-объекты, которые уже будут элементами вашей коллекции. Это дополнительные расходы.
  4. Как вы формируете коллекцию. Скажем, вы используете в качестве коллекции ArrayList. Тогда желательно знать размер коллекции до ее создания, т.к. при использовании конструктора без параметров capacity = 10 по-умолчанию. При переполнении новая capacity = oldCapacity * 3 / 2 + 1 и происходит копирование всех элементов в массив нового размера (System.arrayCopy()). Хоть операция копирования и вылизана до последней строчки, все равно она крайне дорогая.

Я недавно задавал похожий вопрос. Большинство комментаторов, высказалось за то, что особой проблемы нет какой объем данных грузить за один раз из базы данных. Мое мнение из практики: это не совсем так, если грузить достаточно большие данные из базы, затем помещать их в коллекцию, затем в адаптер RecyclerView, тогда даже на топовых устройствах будет подтормаживать. Смотрите обсуждения в упомянутом вопросе, пробуйте и делайте свои выводы.

Вам можно посоветовать две стратегии оптимизации:

  1. Использовать связку SQLiteCursor - RecyclerView напрямую, минуя промежуточную коллекцию. В таком подходе вы напрямую даете cursor c данными в RecyclerView. Вот реализация такого подхода: CursorRecyclerViewAdapter
  2. Подгружать данные не сразу все, а частями, по мере необходимости. Обзор таких подходов смотрите здесь. Недавно вышла от Google библиотека Paging Library, которая организует постраничную подгрузку, можете её глянуть.
Aliaksei
  • 483
  • Спасибо за ответ. Этот пример https://gist.github.com/skyfishjy/443b7448f59be978bc59 я смотрел и плохо понял как адаптировать для существующей БД. И примеров не нашел где было бы реализовано что-то похожее с готовой БД. Везде есть примеры, где создается БД. – Kolhoznik Dec 25 '17 at 10:41
  • 1
    Я не понимаю какая разница есть ли у вас уже база, или она формируется динамически. Вы же спрашиваете как доставать большой объем данных их базы? Да, если у вас уже есть готовая реализация SQLiteOpenHelper, вы как-то получаете там cursor c данными, затем данные из cursor отдаете в коллекцию, и из коллекции в RecyclerView, то все что вам нужно сделать, для использования подхода CursorRecyclerViewAdapter это переписать ваш адаптер, и давать cursor с данными напрямую в адаптер. – Aliaksei Dec 25 '17 at 10:58
  • все правильно, только в вашем вопросе большинство комментаторов высказалось за то, что нет проблемы в том случае, если в адаптер передавать напрямую Cursor. Если перегонять через промежуточный список, то 100% будут лаги. Так же настоятельно рекомендуется использовать CursorLoader – pavlofff Dec 25 '17 at 11:45
  • 1
    @pavlofff так же настоятельно рекомендуется изначально использовать БД Realm :) – YaPV Dec 25 '17 at 11:58
  • 1
    @YaPV На самом деле noSQL решение подходит далеко не для всех ситуаций, в некоторых применениях и явно проигрывает "классической" реляционной БД. Имеется ввиду сам характер хранимых данных и их обработка, а не скорость работы. – pavlofff Dec 25 '17 at 12:07
  • 1
    @pavlofff я не буду спорить, т.к. мой опыт разработки оставляет желать лучшего. Но из Realm тянуть записи из БД можно всего одной строкой: RealmResults list. Кидаем этот list в адаптер и избавляемся от сотен строк кода, присущих sqlite. Если я не прав - поправьте меня :) – YaPV Dec 25 '17 at 12:30
  • А есть какая-нибудь статья, где описано как работать с БД realm, а именно выводить данные в RecyclerView? – Kolhoznik Dec 25 '17 at 13:10
  • 2
    @Kolhoznik оф. дока с огромной кучей примеров. чтобы вы понимали я не агитирую использовать realm. Скажу сугубо по своим ощущениям. Когда я открыл мир БД Realm, я послал sqlite далеко и надолго и больше никогда к ней не возвращался. Для всех моих дел, реалма хватает выше крыши. – YaPV Dec 25 '17 at 13:17
  • Я хотя бы посмотрю что за БД, никогда не работал с ней. Может получится что-то и написать используя эту БД – Kolhoznik Dec 25 '17 at 13:19
  • @YaPV, полностью согласен на счет Realm. Когда начал им пользоваться, ощущения были, как будто новый год настал )) – kulikovman Dec 28 '17 at 09:52
  • @kulikovman так да, наблюдаю, что всё чаще в вакансиях требуют знания именно БД Realm. – YaPV Dec 28 '17 at 17:37
  • Не разделю общих восторгов по поводу Realm. Во-первых, у них ленивая реализация, т.е. вы получаете данные непосредственно когда они начинают использоваться, поэтому прицепить бенчмарк, чтобы померить скорость работы достаточно нетривиально. По субъективным ощущениям выигрыша в скорости нет (по сравнению с SQLite). Во-вторых, Realm не поддерживает передачу объекта между потоками. Хорошо, если запрос легкий и все достаточно быстро работает, чтобы не тормозить UI. Для больших БД не стал бы Realm использовать. – Aliaksei Jan 06 '18 at 14:59