package com.example.myapp.ui.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.myapp.databinding.ItemPostBinding
import com.example.myapp.models.Post
class PostsAdapter(
private val onPostClick: (Post) -> Unit,
private val onLikeClick: (Post) -> Unit = {}
) : ListAdapter<Post, PostsAdapter.PostViewHolder>(PostDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder {
val binding = ItemPostBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return PostViewHolder(binding, onPostClick, onLikeClick)
}
override fun onBindViewHolder(holder: PostViewHolder, position: Int) {
holder.bind(getItem(position))
}
class PostViewHolder(
private val binding: ItemPostBinding,
private val onPostClick: (Post) -> Unit,
private val onLikeClick: (Post) -> Unit
) : RecyclerView.ViewHolder(binding.root) {
fun bind(post: Post) {
binding.apply {
titleText.text = post.title
bodyText.text = post.body
authorText.text = post.author
likesText.text = "${post.likesCount} likes"
timestampText.text = formatTimestamp(post.createdAt)
likeButton.setImageResource(
if (post.isLiked) R.drawable.ic_liked else R.drawable.ic_like
)
root.setOnClickListener { onPostClick(post) }
likeButton.setOnClickListener { onLikeClick(post) }
}
}
private fun formatTimestamp(timestamp: Long): String {
val now = System.currentTimeMillis()
val diff = now - timestamp
val seconds = diff / 1000
val minutes = seconds / 60
val hours = minutes / 60
val days = hours / 24
return when {
days > 0 -> "$days days ago"
hours > 0 -> "$hours hours ago"
minutes > 0 -> "$minutes minutes ago"
else -> "Just now"
}
}
}
class PostDiffCallback : DiffUtil.ItemCallback<Post>() {
override fun areItemsTheSame(oldItem: Post, newItem: Post): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Post, newItem: Post): Boolean {
return oldItem == newItem
}
override fun getChangePayload(oldItem: Post, newItem: Post): Any? {
return if (oldItem.likesCount != newItem.likesCount ||
oldItem.isLiked != newItem.isLiked) {
"LIKES_CHANGED"
} else {
null
}
}
}
}
package com.example.myapp.ui.adapters
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
class SwipeToDeleteCallback(
private val onDelete: (Int) -> Unit
) : ItemTouchHelper.SimpleCallback(
0,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.adapterPosition
onDelete(position)
}
}
// Usage in Fragment:
// val itemTouchHelper = ItemTouchHelper(SwipeToDeleteCallback { position ->
// viewModel.deletePost(adapter.currentList[position])
// })
// itemTouchHelper.attachToRecyclerView(binding.recyclerView)
RecyclerView displays large datasets efficiently with view recycling. I create a ViewHolder to cache view references and an Adapter to bind data. DiffUtil calculates minimal updates using areItemsTheSame and areContentsTheSame callbacks, improving performance over notifyDataSetChanged(). ListAdapter simplifies DiffUtil usage with background diffing. ItemTouchHelper adds swipe and drag gestures. ConcatAdapter combines multiple adapters. Layout managers control positioning—LinearLayoutManager for lists, GridLayoutManager for grids, StaggeredGridLayoutManager for Pinterest-style layouts. ViewBinding eliminates findViewById. Pagination libraries load data incrementally. RecyclerView powers most scrolling lists in Android apps.