ListView: фильтрация через Filterable против перезапуска CursorLoader с новым URI

ListView реализует методы фильтрации содержимого. Не могли бы вы рассказать, когда его следует использовать?

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

Однако, если ListView используется с адаптером курсора (база данных SQLite) для отображения большого количества элементов, данные могут отсутствовать в памяти. С другой стороны, значение фильтра можно встроить в запрос SQL, чтобы эффективно получить сокращенный набор данных.

Был ли механизм фильтрации для ListView разработан также для данных на основе курсора? Когда следует использовать Filterable и когда фильтр следует передавать в запрос SQL без использования фильтров ListView? Есть ли рекомендации, когда использовать тот или иной подход?

Спасибо

P.S. Этот вопрос был отделен от Как должна быть спроектирована система URI?, в которой объединены два предыдущих вопроса.


person pepr    schedule 09.08.2013    source источник


Ответы (2)


Был ли механизм фильтрации для ListView разработан также для данных на основе курсора?

Механизм фильтрации через класс Filter был реализован для адаптера (логическое действие, связанное с адаптером), ListView - просто простой пользователь этого адаптера.

Когда следует использовать Filterable и когда фильтр следует передавать в SQL-запрос без использования фильтров ListView? Есть ли рекомендации, когда использовать тот или иной подход?

Я не думаю, что есть какие-либо рекомендации, какой из них использовать (или я их сам не видел). Однако класс Filter специально разработан для оптимизации процесса фильтрации (например, если начальная операция фильтрации занимает некоторое время, и пользователь делает другие запросы в это время, тогда класс Filter будет выполнять только последнюю запланированную операцию фильтрации (другая операция не выполняется). т смысла делать)). К моему стыду, я не знаю, отменит ли CursorLoader загрузку, если в это время вызывается обратный вызов onLoaderReset(), если он этого не сделает, это будет плохо, потому что вы сделаете все из них (если пользователь сделает фильтрация после abcd fast, вы не захотите делать abcd, вы захотите сделать объявление). Вы могли бы оптимизировать это, но проблемы с фильтром не имели бы смысла.

Однако, если ListView используется с адаптером курсора (база данных SQLite) для отображения большого количества элементов, данные могут отсутствовать в памяти. С другой стороны, значение фильтра можно встроить в запрос SQL, чтобы эффективно получить сокращенный набор данных.

Измерьте вещи. Выполнение новых запросов с большим ограничением сократит набор данных за счет того, что пользователь увидит результат медленнее. Если время неприемлемо, возможно, имеет смысл сделать один запрос (для начального ограничения), а затем отфильтровать этот набор данных без дополнительных запросов sqlite.

person user    schedule 11.08.2013

Вы можете воспользоваться обоими преимуществами. Настройте Filter, но в runQuery() вашего FilterQueryProvider не запускайте полностью новый запрос к базе данных. Просто используйте оболочку вокруг исходного курсора, чтобы отфильтровать то, что вам не нужно. Эту оболочку довольно просто создать, она была упоминается на SO.

Из недавнего опыта: не используйте оба. Filterable выполняет свою собственную фоновую обработку, поэтому, если вы его используете, нет необходимости в каком-либо CursorLoader вообще. На самом деле использование обоих не причиняет реального вреда, но приводит к ненужным запросам и снижению производительности. Ваш runQuery() запрос должен обрабатывать оба случая, нефильтрованный (ограничение пусто) и отфильтрованный (ограничение не пусто), что означает, что все операции запроса выполняются через фильтр и только фильтр. Все, что вам нужно сделать, чтобы запустить его, - это вызвать это в конструкторе вашего адаптера:

setFilterQueryProvider(this);
getFilter().filter(null);

И неприятный сюрприз, который вызвал у меня головную боль. CusorLoader довольно хорошо управляет курсором, даже в строгом режиме, проблем нет, но с Filterable ситуация менее идеальна. Никаких проблем при нормальной работе, он избавляется от старого курсора, но изменения жизненного цикла активности могут его отловить. Решение, которое я нашел, - расширить ваши ListView/RecyclerView представления, которые вы используете с этими адаптерами, и убедиться, что в конце курсор уничтожен:

@Override
protected void onDetachedFromWindow() {
  super.onDetachedFromWindow();
  ((CursorAdapter) getAdapter()).changeCursor(null);
}

В качестве альтернативы, если вы не хотите расширяться, вы можете вызвать то же самое из onDestroy() вашей активности для каждого представления с поддержкой адаптера, но я предпочитаю подход «установил и забыл», который предлагает первый.

person Gábor    schedule 29.12.2014
comment
Спасибо за объяснение. И всего наилучшего в новом году. - person pepr; 07.01.2015