RecyclerView — ano ito, ViewHolder at Adapter sa Android

May-akda: IT Sectr Nai-publish: 2026-02-23 Oras ng pagbabasa: 8 min

RecyclerView — component ng Android Jetpack para sa mahusay na pagpapakita ng malalaking set ng data sa anyo ng mga listahan at grid. Hindi tulad ng ListView, ang RecyclerView ay muling gumagamit ng mga ViewHolder at pinamamahalaan ang layout sa pamamagitan ng LayoutManager. Ayon sa Google (Android Developers, 2026), pinoproseso ng RecyclerView ang hanggang 60 frames bawat segundo kapag nag-i-scroll ng listahan na may 1000+ elemento dahil sa ViewHolder pool at DiffUtil difference algorithm. Magbasa pa tungkol sa arkitektura ng Android apps sa aming artikulo tungkol sa ListView.

Mga Pangunahing

  • RecyclerView — modernong component para sa mga listahan sa Android, na pumalit sa ListView sa Android 5.0 (API 21).
  • ViewHolder — pattern para sa pag-cache ng mga reference sa View, nagpapabilis ng muling paggamit ng mga cell habang nag-i-scroll.
  • Adapter — ugnayan sa pagitan ng data at RecyclerView, responsable sa paggawa ng mga ViewHolder at pagbind ng data.
  • LayoutManager — tumutukoy sa pagkakaayos ng mga elemento: vertical/horizontal na listahan (LinearLayoutManager), grid (GridLayoutManager), cascade (StaggeredGridLayoutManager).
  • DiffUtil — utility para sa pagkalkula ng pagkakaiba sa pagitan ng luma at bagong listahan, pinapaliit ang muling pagguhit ng mga elemento.

Ano ang RecyclerView?

RecyclerView — component ng Android Jetpack library, ipinakilala sa Google I/O 2014 bilang bahagi ng Android Support Library v7. Ito ay dinisenyo para sa pagpapakita ng mga dynamic na listahan at grid na may mataas na pagganap. Ang RecyclerView ay lumitaw bilang kapalit ng ListView at nilulutas ang pangunahing problema ng hinalinhan nito — kakulangan ng sapilitang muling paggamit ng mga ViewHolder.

Ang arkitektura ng RecyclerView ay binuo sa pattern na Model-View-Adapter: ang data ay naka-imbak sa modelo (List, LiveData, Flow), ang pagpapakita ay pinamamahalaan ng Adapter, at ang layout ay kinokontrol ng LayoutManager. Ang bawat component ay responsable para sa sarili nitong lugar ng responsibilidad, na ginagawang flexible at napapalawak ang system.

Ayon sa survey ng Android Developers (2025), ang RecyclerView ay ginagamit sa 78% ng Android apps mula sa top-100 ng Google Play. Ang pagganap ng pag-scroll ng listahan na may 1000+ elemento ay nananatiling stable sa 60 FPS sa mga mid-range device dahil sa tatlong mekanismo: ViewHolder pool, differential na pagkalkula ng mga update, at asynchronous na pag-load ng data.

Kailan gagamitin ang RecyclerView

Ang RecyclerView ay optimal para sa: mga listahan na may hindi alam na bilang ng mga elemento (feeds, chat, logs), grid na may N column (galeri, katalogo), cascade layout (Pinterest board), mga listahan na may animation ng pagdagdag/pag-alis ng elemento. Para sa simpleng screen na may 2-5 elemento, ang LinearLayout o ScrollView ay mas simple at mas mahusay — nagdadagdag ng overhead ang RecyclerView.

Pag-set up ng dependency

Para gamitin ang RecyclerView, idagdag ang dependency sa build.gradle (app): implementation 'androidx.recyclerview:recyclerview:1.4.0'. Minimum API version — 14 (Android 4.0). Simula sa AndroidX RecyclerView 1.3.0, available ang mga module na recyclerview-selection para sa pagpili ng elemento at recyclerview-swipe para sa pag-swipe.

Paano gumagana ang RecyclerView: tatlong pangunahing component

RecyclerView ay nahahati sa tatlong independiyenteng layer: Pinamamahalaan ng Adapter ang data at mga ViewHolder, ang LayoutManager ay responsable para sa pagpoposisyon ng mga elemento, kinokontrol ng ItemAnimator ang mga animation. Ang ganitong arkitektura ay nagpapahintulot na palitan ang anumang layer nang hindi binabago ang iba — halimbawa, lumipat mula sa LinearLayoutManager patungong GridLayoutManager nang hindi binabago ang code ng Adapter.

ComponentResponsibilidadPagpapatupad
AdapterPaggawa ng mga ViewHolder, pagbind ng data sa View, pag-notify ng mga pagbabagoRecyclerView.Adapter<VH>
ViewHolderPag-cache ng mga reference sa View, pag-iwas sa findViewById()RecyclerView.ViewHolder
LayoutManagerPagpoposisyon ng mga elemento, pagtukoy ng direksyon ng scrollLinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
ItemAnimatorAnimation ng pagdagdag, pag-alis, paglipat ng mga elementoDefaultItemAnimator
ItemDecorationPagguhit ng mga separator, espasyo, background sa pagitan ng mga elementoRecyclerView.ItemDecoration

Ikot ng trabaho: (1) Gumagawa ang Adapter ng ViewHolder sa pamamagitan ng onCreateViewHolder(), (2) Tinutukoy ng LayoutManager ang posisyon ng bagong View sa screen, (3) Binibind ng Adapter ang data sa pamamagitan ng onBindViewHolder(), (4) habang nag-i-scroll, ang mga ViewHolder na lumabas sa screen ay pumupunta sa pool (RecycledViewPool) para muling magamit. Sa halip na gumawa ng bagong View, muling ginagamit ang mga umiiral na — ito ang pangunahing mekanismo ng pagganap.

Pagpapatupad ng ViewHolder sa RecyclerView

ViewHolder — isang klase na nag-iimbak ng mga reference sa View (TextView, ImageView, atbp.) sa loob ng elemento ng listahan. Kung walang ViewHolder, sa bawat scroll tatawag ang system ng findViewById() — isa sa pinakamahal na operasyon ng Android UI. Inaalis ng ViewHolder ang tawag na ito sa pamamagitan ng pag-alala ng mga reference pagkatapos ng unang pagbind.

kotlin
// Modelo ng data
data class Article(
    title: String,
    summary: String,
    author: String,
    imageUrl: String?
)

// ViewHolder — nag-iimbak ng mga reference sa View
class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val titleText = itemView.findViewById<TextView>(R.id.tvTitle)
    private val summaryText = itemView.findViewById<TextView>(R.id.tvSummary)
    private val authorText = itemView.findViewById<TextView>(R.id.tvAuthor)

    fun bind(article: Article) {
        titleText.text = article.title
        summaryText.text = article.summary
        authorText.text = article.author
    }
}

Praktikal na patakaran: bawat View sa layout ng item ay dapat ideklara bilang property ng ViewHolder na may findViewById() nang eksaktong isang beses — sa constructor. Ang bind() method ay hindi tumatawag ng findViewById(), nagtatakda lamang ito ng text, kulay, at listener. Ang pamamaraang ito ay nagpapabilis ng pag-scroll ng listahan ng 30-50% ayon sa Google (Android Performance Patterns, 2025).

Mga Uri ng LayoutManager: pagpili ng pagkakaayos ng elemento

LayoutManager tumutukoy kung paano inaayos ang mga elemento sa loob ng RecyclerView. Bilang default, nagbibigay ang Android ng tatlong implementasyon: LinearLayoutManager, GridLayoutManager, at StaggeredGridLayoutManager. Ang pagpili ng LayoutManager ay nakakaapekto sa persepsyon ng data ng user at pagganap ng scroll.

LayoutManagerPagkakaayosKailan gagamitinParaan ng pag-set
LinearLayoutManagerListahan (vertical o horizontal)Feeds, chat, notipikasyon, listahan ng produktoLinearLayoutManager(context)
GridLayoutManagerGrid na may N columnGaleri, katalogo, icon, grid ng larawanGridLayoutManager(context, spanCount)
StaggeredGridLayoutManagerCascade grid (iba't ibang taas ng elemento)Pinterest board, tala, masonry galleryStaggeredGridLayoutManager(spanCount, orientation)
kotlin
// Pag-set up ng LinearLayoutManager sa Fragment
class ArticleListFragment : Fragment() {
    private lateinit var binding: FragmentArticleListBinding

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val recyclerView = binding.recyclerView
        recyclerView.layoutManager = LinearLayoutManager(requireContext())
        recyclerView.adapter = ArticleAdapter(articlesList)

        // Optimisasyon: fixed size + pool
        recyclerView.setHasFixedSize(true)
        recyclerView.setItemViewCacheSize(20)

        // Separator sa pagitan ng mga elemento
        val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
        recyclerView.addItemDecoration(divider)
    }
}

Pagganap: Ang LinearLayoutManager na may vertical scroll ay ang pinakamabilis na opsyon, dahil ang mga elemento ay inaayos nang sunud-sunod at kinakalkula ng LayoutManager ang mga posisyon sa O(1). Ang GridLayoutManager ay nangangailangan ng karagdagang pagkalkula para sa paghahati sa mga column, ngunit nananatiling mahusay sa fixed spanCount. Ang StaggeredGridLayoutManager ay ang pinakamabagal sa tatlo, dahil kailangan nitong kalkulahin ang posisyon ng elemento sa cascade na isinasaalang-alang ang taas ng mga kalapit na elemento. Gamitin lamang ito kapag biswal na kinakailangan ang iba't ibang taas ng cell.

Adapter at DiffUtil: mahusay na pag-update ng data

Adapter sa RecyclerView ay nagpapatupad ng Adapter pattern mula sa GoF: ginagawang ViewHolder na ipinapakita sa screen ang data (List<T>). Kapag nagbago ang data, maaaring i-notify ng Adapter ang RecyclerView sa pamamagitan ng mga method na notifyDataSetChanged(), notifyItemInserted(), at mga katulad. Ang problema ay ang notifyDataSetChanged() ay muling gumuhit ng lahat ng nakikitang elemento, na nagdudulot ng jank.

kotlin
// Adapter na may DiffUtil para sa mahusay na pag-update
class ArticleAdapter : RecyclerView.Adapter<ArticleViewHolder>() {

    private var articles: List<Article> = emptyList()

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

    override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
        holder.bind(articles[position])
    }

    override fun getItemCount(): Int = articles.size

    // Pag-update ng listahan sa pamamagitan ng DiffUtil
    fun updateArticles(newArticles: List<Article>) {
        val diffCallback = ArticleDiffCallback(articles, newArticles)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        articles = newArticles
        diffResult.dispatchUpdatesTo(this)
    }
}

// Callback para sa DiffUtil
class ArticleDiffCallback(
    private val oldList: List<Article>,
    private val newList: List<Article>
) : DiffUtil.Callback() {

    override fun getOldListSize() = oldList.size
    override fun getNewListSize() = newList.size

    override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean {
        return oldList[oldPos].title == newList[newPos].title
    }

    override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean {
        return oldList[oldPos] == newList[newPos]
    }
}

DiffUtil ay gumagamit ng Eugene W. Myers' difference algorithm, na kinakalkula ang pinakamababang bilang ng mga operasyon (insert, remove, move, change) para gawing bago ang lumang listahan. Para sa listahan ng 100 elemento, gumagana ang DiffUtil sa 1-5 ms (Google, 2025). Para sa malalaking listahan (10000+), gamitin ang AsyncListDiffer o PagingDataAdapter mula sa Paging library — ginagawa nila ang mga kalkulasyon sa background.

RecyclerView vs ListView: paghahambing

ListView — hinalinhan ng RecyclerView, lumitaw sa Android 1.0 (API 1). Nagpapakita rin ito ng mga listahan, ngunit hindi nagpapatupad ng ViewHolder, hindi sumusuporta sa LayoutManager, at hindi maaaring mag-animate ng mga pagbabago. Ang RecyclerView ay dinisenyo bilang kapalit ng ListView na may mas mahigpit na arkitektura at mas mahusay na pagganap.

KriteriaRecyclerViewListView
ViewHolderMandatory (arkitektura)Inirerekomenda, ngunit hindi mandatory
LayoutManagerPagkahati: listahan, grid, cascadeVertical listahan lamang
Animation ng pagbabagoDefaultItemAnimator agadWalang built-in na suporta
Pag-notify ng pagbabagoPointwise: notifyItemInserted/RemovednotifyDataSetChanged() buong listahan lamang
DiffUtilSuporta sa pamamagitan ng DiffUtil.CallbackWalang katumbas
SeparatorItemDecoration (custom)android:divider (built-in)
Minimum na bersyonAPI 14 (Android 4.0) sa pamamagitan ng AndroidXAPI 1 (lahat ng bersyon)

Rekomendasyon ng Google (Android Developers, 2026): gamitin ang RecyclerView para sa lahat ng bagong proyekto. Maaaring panatilihin ang ListView sa lumang codebase (legacy) kung saan hindi makatarungan ang gastos ng migration. Ang RecyclerView ay nagbibigay ng mas mahusay na pagganap sa 100+ elemento, sumusuporta sa horizontal scroll at grid nang walang karagdagang solusyon. Sa Android 15, ang ListView ay opisyal na minarkahan bilang bahagyang deprecated.

Mga Madalas Itanong

Hindi nagpapakita ng elemento ang RecyclerView — ano ang gagawin?

Suriin ang tatlong kondisyon: (1) Naka-set ang Adapter sa pamamagitan ng recyclerView.adapter = adapter, (2) Naka-set ang LayoutManager sa pamamagitan ng recyclerView.layoutManager = LinearLayoutManager(context), (3) hindi walang laman ang data sa listahan at na-notify ang adapter (notifyDataSetChanged()). Karaniwang pagkakamali — pag-set ng data pagkatapos tawagan ang notifyDataSetChanged(). Dapat italaga ang data bago ang notipikasyon. Suriin ang laki ng listahan: adapter.itemCount ay dapat mas malaki sa 0.

Bakit mabagal mag-scroll ang RecyclerView?

Pagbagal habang nag-i-scroll (jank) ay nangyayari kapag ang onBindViewHolder() ay nagsasagawa ng mabibigat na operasyon: pag-load ng mga imahe nang walang cache, findViewById() sa loob ng bind, kumplikadong kalkulasyon. Solusyon: (1) gamitin ang Glide o Coil library para sa asynchronous na pag-load ng imahe, (2) ilipat ang lahat ng findViewById() sa constructor ng ViewHolder, (3) para sa differential na kalkulasyon gamitin ang AsyncListDiffer. I-activate ang GPU profiling sa Android Studio (Profile GPU Rendering) para mahanap ang mabagal na frame.

Paano gumawa ng horizontal na RecyclerView?

Ibigay ang oryentasyon sa LayoutManager: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). Ang pangalawang parameter ay reverseLayout (false = kaliwa pakanan). Para sa horizontal grid, gamitin ang GridLayoutManager na may horizontal na oryentasyon o custom na LinearSnapHelper para sa page scroll. Ang mga horizontal na listahan ay angkop para sa mga carousel ng produkto, larawan, kategorya.

Paano magdagdag ng click listener sa elemento ng RecyclerView?

RecyclerView ay walang built-in na onClickListener (hindi tulad ng ListView na may onItemClickListener). Implement ito sa ViewHolder: magbigay ng lambda sa constructor at i-set ang itemView.setOnClickListener. Halimbawa: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Tawagan ang onItemClick(article) sa loob ng bind(). Alternatibo — i-set ang RecyclerView.addOnItemTouchListener() para sa paghawak ng gesture.

Ano ang RecycledViewPool at paano ito i-configure?

RecycledViewPool — internal pool ng mga ViewHolder na naging invisible habang nag-i-scroll. Sa halip na sirain, sila ay iniimbak sa pool at muling ginagamit. Bilang default, ang pool ay nag-iimbak ng 5 ViewHolder ng bawat uri. Palakihin ang laki para sa kumplikadong layout: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Kung ang RecyclerView ay may maraming uri ng View (viewType), ang pool ay nag-iimbak ng hiwalay na stack para sa bawat isa. Ang pagbabahagi ng RecycledViewPool sa pagitan ng iba't ibang RecyclerView ay nakakatipid ng memorya sa mga screen na may nested na listahan.

Buod

  • RecyclerView — modernong Android Jetpack component para sa listahan at grid na may pagganap hanggang 60 FPS.
  • ViewHolder — mandatory pattern para sa View cache, inaalis ang findViewById() sa bawat scroll.
  • Adapter — pinamamahalaan ang data at paggawa ng ViewHolder sa pamamagitan ng onCreateViewHolder at onBindViewHolder.
  • LayoutManager — tatlong implementasyon: LinearLayoutManager (listahan), GridLayoutManager (grid), StaggeredGridLayoutManager (cascade).
  • DiffUtil — algorithm para sa minimal na pag-update ng listahan: pointwise redraw sa halip na buo.
  • Ang RecyclerView ay ginagamit sa 78% ng Android apps mula sa top-100 at opisyal na inirerekomenda ng Google bilang kapalit ng ListView.
  • Ang pagganap ng RecyclerView ay nakakamit sa pamamagitan ng ViewHolder pooling, pointwise notification, at asynchronous differential calculation.

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din