RecyclerView: фильтр отображения единственной коллекции

Есть рабочий Adapter: RecyclerView.Adapter
Но он отображает весь список arr
Я же хочу, чтобы он отображал только элементы при условии (пример), что поле элемента Tovar.coast > 100
Я знаю, что можно создать новый List с этим условием и отобразить его.
Но можно ли как-то сделать это на имеющимся массиве, без создания нового?

 class TovarAdapter(
            var app: AppCompatActivity,
            var arr: MutableList<Tovar>
    ) : RecyclerView.Adapter<TovarAdapter.MyHolder>() {
    

    class MyHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
        val infalter = LayoutInflater.from(parent.context)
        val itemView = infalter.inflate(R.layout.item_tovar, parent, false)
        val holder = MyHolder(itemView)      
        return holder
    }

    override fun getItemCount(): Int {
        return arr.size
    }

    override fun onBindViewHolder(holder: MyHolder, position: Int) {
        holder.itemView.findViewById<TextView>(R.id.item_name_tx).setText("${arr[position].name}")
}

суть моей проблемы:
есть список товаров (класс). у каждого объекта есть поля "имя, цена, избранное (boolean)"

товары можно "добавлять / удалять / редактировать"

есть кнопка "показать только избранное"

когда она нажимается - на основе основного массива, по критерию "избранное == true" создается новый список товаров и скармилвается Адаптеру.
редактируются эти элементы хорошо. ведь в обоих списках лежат просто ссылки на объекты.

а вот если я включил "показать избранные" и пытаюсь удалить товар - он удаляется только из "временного" массива, созданного для отображения только избранного.
конечно же, я добавил проверку "у нас настоящий массив или временный? если временный - найти и удалить этот объект из настоящего".
но мне этот вариант душу не греет))


Ответы (2 шт):

Автор решения: Vlad Orlinskas

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

class Adapter : RecyclerView.Adapter<Adapter.Holder>() {

    var clickListener: ((Client) -> (Unit))? = null

    private val _items = mutableListOf<Client?>()

    var items: List<Client?>
        get() = _items
        set(value) {
            _items.clear()
            // обрабатываейте данные здесь
            // например используйте filter { ваше условие }
            _items.addAll(value)
            notifyDataSetChanged()
        }

override fun onBindViewHolder(holder: Holder, position: Int) {
           val item = _items[position]
           заполняйте view или используйте databinding 
           view.setOnClickListener {
               clickListener?.invoke(item)
           }
}

// не забудьте переопределить другие методы
    override fun getItemCount() = _items.size

}

Таким образом, вам не нужно создавать новый инстанс, что бы заполнить адаптер другими данными. Теперь у вас есть место, что бы использовать другие методы адаптера, например notifyItemInserted .

Как это использовать в актвити или фрагменте:

class ClientsFragment : Fragment() {

   private val adapter by lazy { ClientAdapter() }

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // получите данные
        adapter.items = it
        adapter.clickListener = { client ->
           // ваш колбек от слушателя нажатий
        }

}
→ Ссылка
Автор решения: Wlad

придумал костыль.
как меня и предупреждали в комментах - тормоза UI видны даже при размере массива 5-10 шт.

в методе отображения элементов я добавил блок проверки по нужному критерию и просто задал размеры это View по высоте и ширине = 0. и скрыл ее (хотя это и не обязательно).
так же добавил return чтобы попытаться облегчить муки (хотя это и не очень помогает)

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

было:

override fun onBindViewHolder(holder: MyHolder, position: Int) {
        holder.itemView.findViewById<TextView>(R.id.item_name_tx).setText("${arr[position].name}")
}

стало:

override fun onBindViewHolder(holder: MyHolder, position: Int) {
        if (arr[position].coast < 100) {
            holder.itemView.layoutParams.height = 0
            holder.itemView.layoutParams.width = 0
            holder.itemView.visibility = View.GONE
            return

        }
        holder.itemView.findViewById<TextView>(R.id.item_name_tx).setText("${arr[position].name}")
    }
→ Ссылка