Что такое RecyclerView.Adapter?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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
- onBindViewHolder должен быть быстрым — выполняйте тяжёлые операции в фоне
- Переиспользуйте View — не создавайте новые в onBindViewHolder
- Используйте ListAdapter — для лучшей производительности
- DiffUtil — правильно вычисляет изменения для гладкой анимации
- ViewBinding — безопаснее чем findViewById
Adapter — это сердце RecyclerView, и его оптимизация критична для производительности приложения.