← Назад к вопросам

Что такое RecyclerView.Adapter?

1.3 Junior🔥 171 комментариев
#Android компоненты#UI и вёрстка

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

RecyclerView.Adapter — мост между данными и UI

RecyclerView.Adapter — это компонент, который связывает набор данных с представлением элементов в RecyclerView. Это паттерн Adapter из Gang of Four, который преобразует данные в видимые элементы интерфейса. Adapter отвечает за создание, переиспользование и обновление элементов списка.

Зачем нужен Adapter?

RecyclerView содержит потенциально бесконечное количество элементов, но экран может вместить только несколько. Adapter:

  • Создаёт элементы (View) по мере необходимости
  • Переиспользует элементы, когда они уходят за пределы экрана
  • Связывает данные с каждым элементом
  • Уведомляет RecyclerView об изменениях данных

Это позволяет создавать гладкие списки с миллионами элементов без огромного потребления памяти.

Структура Adapter

class UserAdapter(private val users: List<User>) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
    inner class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val nameTextView: TextView = itemView.findViewById(R.id.user_name)
        private val emailTextView: TextView = itemView.findViewById(R.id.user_email)
        
        fun bind(user: User) {
            nameTextView.text = user.name
            emailTextView.text = user.email
        }
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val itemView = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_user, parent, false)
        return UserViewHolder(itemView)
    }
    
    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(users[position])
    }
    
    override fun getItemCount(): Int = users.size
}

Три ключевых метода

1. onCreateViewHolder() — создание элемента:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val view = LayoutInflater.from(parent.context)
        .inflate(R.layout.item_layout, parent, false)
    return ViewHolder(view)
}

Вызывается редко, только когда нужен новый элемент.

2. onBindViewHolder() — привязка данных:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val item = data[position]
    holder.textView.text = item.title
    holder.imageView.setImageUrl(item.imageUrl)
}

Вызывается часто и должен быть быстрым.

3. getItemCount() — размер данных:

override fun getItemCount(): Int = data.size

Полный пример

data class Product(val id: Int, val name: String, val price: Double)

class ProductAdapter(
    private val products: List<Product>,
    private val clickListener: (Product) -> Unit
) : RecyclerView.Adapter<ProductAdapter.ProductViewHolder>() {
    
    inner class ProductViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val nameTextView: TextView = itemView.findViewById(R.id.product_name)
        private val priceTextView: TextView = itemView.findViewById(R.id.product_price)
        
        fun bind(product: Product) {
            nameTextView.text = product.name
            priceTextView.text = "\$${product.price}"
            itemView.setOnClickListener { clickListener(product) }
        }
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_product, parent, false)
        return ProductViewHolder(view)
    }
    
    override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
        holder.bind(products[position])
    }
    
    override fun getItemCount(): Int = products.size
}

val adapter = ProductAdapter(products) { product ->
    Toast.makeText(this, "Clicked: ${product.name}", Toast.LENGTH_SHORT).show()
}
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)

Типы ViewHolder'ов

class NewsAdapter(private val items: List<Any>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    
    companion object {
        const val TYPE_ARTICLE = 0
        const val TYPE_AD = 1
    }
    
    override fun getItemViewType(position: Int): Int = when (items[position]) {
        is Article -> TYPE_ARTICLE
        is Advertisement -> TYPE_AD
        else -> TYPE_ARTICLE
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            TYPE_ARTICLE -> ArticleViewHolder(/* ... */)
            TYPE_AD -> AdViewHolder(/* ... */)
            else -> ArticleViewHolder(/* ... */)
        }
    }
    
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = items[position]) {
            is Article -> (holder as ArticleViewHolder).bind(item)
            is Advertisement -> (holder as AdViewHolder).bind(item)
        }
    }
    
    override fun getItemCount(): Int = items.size
}

Обновление данных

class UserAdapter(private val users: MutableList<User>) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
    
    fun updateUsers(newUsers: List<User>) {
        users.clear()
        users.addAll(newUsers)
        notifyDataSetChanged()
    }
    
    fun addUser(user: User) {
        users.add(user)
        notifyItemInserted(users.size - 1)
    }
    
    fun removeUser(position: Int) {
        users.removeAt(position)
        notifyItemRemoved(position)
    }
    
    fun updateUser(position: Int, user: User) {
        users[position] = user
        notifyItemChanged(position)
    }
}

Современный подход: ListAdapter

class UserListAdapter : ListAdapter<User, UserListAdapter.UserViewHolder>(UserDiffCallback()) {
    
    class UserDiffCallback : DiffUtil.ItemCallback<User>() {
        override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
            return oldItem.id == newItem.id
        }
        
        override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
            return oldItem == newItem
        }
    }
    
    inner class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(user: User) { /* ... */ }
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_user, parent, false)
        return UserViewHolder(view)
    }
    
    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(getItem(position))
    }
}

val adapter = UserListAdapter()
recyclerView.adapter = adapter
adapter.submitList(newUsers)

Best Practices

  1. onBindViewHolder должен быть быстрым — выполняйте тяжёлые операции в фоне
  2. Переиспользуйте View — не создавайте новые в onBindViewHolder
  3. Используйте ListAdapter — для лучшей производительности
  4. DiffUtil — правильно вычисляет изменения для гладкой анимации
  5. ViewBinding — безопаснее чем findViewById

Adapter — это сердце RecyclerView, и его оптимизация критична для производительности приложения.

Что такое RecyclerView.Adapter? | PrepBro