4

Пишу приложение на Android, где у меня есть некоторый список (RecyclerView), в котором есть возможность перетаскивания (drag & drop) строк в нужное для пользователя место (выше/ниже относительно друг друга). Элементы списка (строки) могут быть разных классов (под общим интерфейсом). Информация о созданных экземплярах, соответственно, хранится в SQLite.

На данный момент, сортировка списка всех элементов списка происходит по дате (при создании списка сортируются в TreeSet'е и потом ArrayList'ом отдаются в адаптер). Таким образом, при изменении порядка отображения элементов списка мне необходимо зафиксировать этот порядок и сохранить его в БД (или может просто в JSON?).
Какие существуют, так сказать, лучшие практики сохранения и извлечения состояния такого списка (да и вообще, подобных данных)?

Заранее благодарен!

1 Answers1

5

Вам не нужно перегонять данные из БД в какие то локальные массивы. Работайте напрямую с базой данных, она имеет на порядок более мощный, чем "жалкие" методы коллекций, язык SQL, специально предназначеный для обработки, сортировки и тп. данных, содержащихся в базе, а так же выполняет эту обработку на порядки же быстрее, чем Java.

Сам подход, который вы пытаетесь применить выглядит несколько нелогично. Зачем хранить данные в БД, но обрабатывать их какими то примитивными и медленными способами, при этом еще тратя время и на промежуточное извлечение из БД в массив, потом еще в другой массив.

По вопросу - вам не нужно сохранять какой то измененный порядок сортировки, переписывая БД. Вам нужен правильный запрос в БД, который вернет данные (курсор), отсортированные в нужном порядке, именно так это делается. Затем этот курсор, в котором уже все отсортированно как надо через SQL-запрос, вы передаете непосредственно в адаптер списка и заполняете сам список данными из курсора, а не из каких то ArrayList-ов.

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

То есть, примерная схема - делаем выборку из БД с сортировкой по времени, заполняем этой выборкой список, при перетаскивании пишем в БД позицию, в которую перетащили (в столбец пользовательской сортировки для записи, которую перетащили), обновляем адаптер через выборку с сортировкой по столбцу с этими позициями - все просто и прозрачно

Это будет правильная архитектура работы с БД, а то, что пытаетесь сделать вы, какой то любительский костыль, простите за резкость, надеюсь это поможет понять вам всю глубину заблуждений :)

Так же смотрите этот ответ по сортировке в БД

pavlofff
  • 36,765
  • 2
    За что минусуем? У вас нелогичная архитектура и работа с БД. Человек направляет по правильному пути, предлагая оптимальный путь извлечения и сохранения данных в БД. Собственно, это и есть ответ на Ваш вопоос – whalemare Jul 18 '16 at 03:57
  • Хм, а как сортировка в базе поможет запомнить созданный юзером при помощи перетаскивания порядок элементов? (И неужели сортировка пары десятков элементов в памяти дороже обращения к базе?) – VladD Jul 18 '16 at 06:55
  • @VladD Дело даже не в "накладных расходах", а в используемой архитектуре. Для пары десятков элементов, возможно, вообще использовать БД не имеет смысла.Насчет "расходов" обоих подходов. Если бы данные изначально были не в БД, то сортировка в памяти может быть и сравнялась бы по скорости с сортировкой в БД, а при небольшом количестве элементов вообще не имела бы большого значения, поскольку обе операции выполнялись бы достаточно быстро, НО! здесь нужно сначала получить данные из БД, затем перегнать их по одному в TreeSet, потом еще по одному в ArrayList и только потом вывести. – pavlofff Jul 18 '16 at 08:05
  • Этот путь может и должен быть значительно короче. Выборка из БД уже отсортированных данных и работа непосредственно с выборкой. Начет пользовательской сортировки добавил в ответ. – pavlofff Jul 18 '16 at 08:05
  • Так же при записи в БД изменений, очевидно, опять же предполагается перебирать этот ArrayList по одному элементу и записывать что то в БД из этого листа - такой подход и для чтения и для записи крайне не оптимизирован и ущербен по своей сути, являясь насмешкой над всей дисциплиной СУБД. – pavlofff Jul 18 '16 at 08:18
  • @pavlofff: Окей, даже допустим. Но всё же, у ТС юзкейс — юзер перетаскивает элементы в списке вручную, нужно сериализовать. Как этого добиться через запросы к базе? – VladD Jul 18 '16 at 08:35
  • @VladD Весь этот юзкейс изначально неправильный и от него следует отказаться. Примерная схема - делаем выборку из БД с сортировкой по времени, заполняем этой выборкой список, при перетаскивании пишем в БД позицию, в которую перетащили, обновляем адаптер через выборку с сортировкой по столбцу с этими позициями - все просто и прозрачно – pavlofff Jul 18 '16 at 08:50
  • @pavlofff: Подождите-подождите, а если вот конкретно клиент говорит — хочу возможность сделать вот эту штуку на первом месте, а вот эту после неё, без всяких логических критериев, просто потому, что мне так хочется? Запретим? – VladD Jul 18 '16 at 09:01
  • 1
    @VladD я не вижу здесь никакой проблемы, как пользователь расположит элементы, так они и будут отображаться, в алгоритме нет никаких логических критериев - чем меньше число в столбце пользовательской сортировки, тем выше в списке будет этот элемент или мы не понимаем друг друга. Автору изначльно надо сортировку по времени, если нужна сразу по определенному порядку, то делать выборку сразу по столбцу пользовательской сортировки. При заполнении БД указать там первоначальный порядок следования элементов – pavlofff Jul 18 '16 at 09:07
  • Я согласен, что сам подход, мягко говоря, кривой и был сделан, чтобы просто работало. Поэтому и задался этим вопросом. Нельзя так это оставлять))) Конечно, элементы не по одному перегоняются в Сеты и Массивы, но не суть. Вы уже дали верный ответ - добавить столбец для пользовательской сортировки и напрямую передавать в курсор (я работаю с ORMLite, но смысл один). Спасибо! – Dmitry Sokolov Jul 18 '16 at 12:24
  • @DmitrySokolov Если вы использете ORM (то есть POJO-модели), а не чистую SQLite, то об этом стоило сказать .. Если вы зашли еще не слишком далеко, то рекомендовал бы сменить ORM на Realm - это чистая ORM, а не надстройка над SQLite, сответственно гораздо более быстрая, так же имеет более развитый API и естественныи образом использует POJO-модели - изначально расчитана на работу с ними (еще имеет уже реализованный адаптер для RecyclerView и некторые другие приемущества) – pavlofff Jul 18 '16 at 13:34
  • @pavlofff Вероятно можно сказать, что я зашел слишком далеко) В любом случае спасибо за наводку! При выборе ORM, по каким-то причинам я пропустил Realm из выборки (плохо искал видимо). Я не думаю, что скорость ORM, в моем случае будет заметна между ORMLite и Realm (даже в теории), но то что я увидел по предоставленной вами ссылке мне определено понравилось! Попробую поработать с Realm в следующем проекте. – Dmitry Sokolov Jul 18 '16 at 14:01