Как правильно реализовать поиск по RecyclerView?
Подскажите как лучше реализовать поиск по RecyclerView В моей БД (и соответственно в RecyclerView) около 300 строк. Запрос поиска в реальном времени слушается в EditText. И я вижу 2 варианта:
- Recycler заполнить напрямую из БД через Cursor, при каждом изменении символа в EditText создавать новый Cursor ( делать поиск запросом в SQL ) и отдавать адаптеру, обновлять данные в адаптере. Т.е поиск средствами самой БД.
- Сделать массив объектов (ArrayList) из БД, заполнить им Recycler и реализовывать самому поиск в массиве по полю объекта, обновляя данные массива для поиска, и отдавать в адаптер.
Как будет правильнее и оптимальнее с точки зрения скорости работы?
Ответы (1 шт):
Автор решения: Viktor
→ Ссылка
Вот так я реализовал подобное у себя. Функция filter() содержит логику поиска и показа результатов. Вызов этой функции нужно делать в функции afterTextChanged в TextWatcher, который нужно привязать к поисковому полю. В коде есть корутины, чтобы избежать лагов в приложении. Код без корутин и специфичных функций приложу ниже оригинального.
//функция принимает на вход поисковой запрос
fun filter(text: String) {
//пустой список, в котором будут находится элементы, удовлетворяющие запросу
val filteredList = mutableListOf<Notes>()
launch(Dispatchers.Main) {
// mainList - переменная, содержащая все данные из БД
mainList = withContext(Dispatchers.IO) { mainViewModel.getData() }
// тут цикл берет каждый элемент списка, превращает весь текст в текст нижнего регистра, что поиск работал корректно, а потом проверяет, содержит ли текущий элемент поисковой запрос и если да, то он добавляется в новый специальный список
for (item in mainList) {
item.text?.let {
if (it.toLowerCase(Locale.ROOT).contains(text.toLowerCase(Locale.ROOT))) {
filteredList.add(item)
}
}
}
// тут я главный список делаю равным поисковому, т.к. он мне нужен для обеспечения такой же кликабельности элементов в активити для других задач, в противном случае этот список будет просто декорацией(в моем случае недопустимо)
mainList = filteredList
// здесь результат поиска присваиваем к главному адаптеру(в адаптере должна быть соответствующая функция setList())
notesAdapter.setList(filteredList)
}
}
Код без корутин и let:
fun filter(text: String) {
val filteredList = mutableListOf<Notes>()
for (item in mainList) {
if (item.text.toLowerCase(Locale.ROOT).contains(text.toLowerCase(Locale.ROOT))) {
filteredList.add(item)
}
}
mainList = filteredList
notesAdapter.setList(filteredList)
}