Lazy Loading — estratehiya ng naantalang pag-load ng data, mga imahe at mga component, kung saan ang mga resources ay hinihiling hindi sa pagsisimula ng app, kundi sa sandaling kailanganin sila ng user. Ayon sa Android Paging 3 Guide, ang tamad na pag-load ng mga listahan ay nagbabawas ng konsumo ng memorya ng 60–80% kapag nagtatrabaho sa malalaking set ng data. Naantalang pagsisimula — ang pangunahing prinsipyong pinagbabatayan ng lahat ng implementasyon ng Lazy Loading.
Mga pangunahing punto
Lazy Loading (tamad na pag-load, naantalang pag-load) — pattern ng disenyo at optimisasyon kung saan ang mga resources ng app ay nilo-load hindi sa pagsisimula, kundi bago gamitin. Sa mobile development, ang Lazy Loading ay inilalapat sa tatlong pangunahing kategorya: data (paginasyon ng mga listahan), mga imahe (pag-load habang nag-i-scroll) at mga component (mga tamad na stack at view).
Ang kabaligtaran ng Lazy Loading ay Eager Loading (masugid na pag-load), kapag ang lahat ng resources ay nilo-load sa pagsisimula ng screen. Ang Eager Loading ay mas simple sa implementasyon, ngunit kumokonsumo ng mas maraming memorya at nagpapahaba ng oras ng unang pagpapakita. Para sa mga listahan na may libu-libong elemento, ang Eager Loading ay humahantong sa OOM (Out of Memory) sa mga device na may limitadong memorya. Nilulutas ng Lazy Loading ang problemang ito sa pamamagitan ng pag-load lamang ng nakikita sa screen at pagdaragdag ng natitira habang nag-i-scroll.
Sa konteksto ng iOS at Android, ang Lazy Loading ay implementado sa iba't ibang antas. Ang SwiftUI ay nagbibigay ng LazyVStack at LazyHStack para sa tamad na rendering. Ang UIKit ay gumagamit ng UITableView na may dequeueReusableCell. Android — RecyclerView na may pool ng ViewHolder. Sa antas ng data — Room na may Paging 3 at Core Data na may NSFetchedResultsController. Ang pagpili ng tiyak na teknolohiya ay depende sa stack at mga kinakailangan sa pagganap.
Ang sentral na prinsipyo ng Lazy Loading — pag-load ng eksaktong dami ng data na kinakailangan para sa kasalukuyang estado ng screen, kasama ang paunang buffer para sa maayos na pag-scroll. Ang approach na ito ay batay sa dalawang mekanismo: pagsubaybay sa visibility at virtualisasyon ng mga elemento.
Mekanismo ng pagsubaybay ay tumutukoy kung aling mga elemento ang nasa nakikitang lugar ng screen (viewport). Sa Android, ginagawa ito ng LinearLayoutManager o GridLayoutManager sa pamamagitan ng mga pamamaraang findFirstVisibleItemPosition at findLastVisibleItemPosition. Sa iOS, ang UIScrollView ay nagbibigay ng bounds.origin.y at contentOffset.height para sa pagkalkula ng nakikitang lugar. Kapag ang elemento ay pumasok sa viewport (o prefetch buffer), magsisimula ang pag-load nito. Kapag iniwan ng elemento ang screen, ang mga resources nito ay maaaring palayain o ilipat sa cache.
// Android — pagsubaybay sa visibility sa RecyclerView
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val lastVisible = layoutManager.findLastVisibleItemPosition()
val totalCount = layoutManager.itemCount
// Nil-load namin ang susunod na pahina kung may natitira pang mas mababa sa 5 elemento < 5 elemento
if (lastVisible >= totalCount - 5) {
loadMoreItems()
}
}
})
Prefetch buffer — paunang pag-load ng mga elementong malapit nang lumitaw sa screen. Sinusuportahan ng RecyclerView ang GapWorker.Prefetch sa pamamagitan ng layoutManager.setItemPrefetchEnabled(true). Sinusuportahan ng iOS UITableView ang prefetching sa pamamagitan ng UITableViewDataSourcePrefetching. Ang laki ng prefetch buffer ay karaniwang 1–2 screen sa unahan, na nagbibigay ng kompromiso sa pagitan ng kinis ng pag-scroll at konsumo ng memorya. Masyadong malaki na prefetch buffer ay sumisira sa mga bentahe ng Lazy Loading, masyadong maliit — lumilikha ng mga bakanteng lugar sa mabilis na pag-scroll.
Mga imahe — ang pinakamabigat na uri ng resources sa mga mobile app. Isang 12 MP na larawan ay maaaring sumakop ng 3–5 MB sa hindi naka-compress na anyo. Ang Lazy Loading ng mga imahe ay pumipigil sa pag-load ng daan-daang hindi nakikitang mga larawan sa memorya, na magiging nakamamatay para sa mga listahan ng mga komento ng user o mga katalogo ng produkto.
Glide — ang pinakasikat na library ng pag-load ng imahe para sa Android na may suporta para sa caching, mga pagbabago at mga animation. Coil — isang mas magaan na alternatibo na isinulat sa Kotlin gamit ang mga coroutine. Ang parehong library ay awtomatikong humihinto sa pag-load kapag ang ImageView ay umalis sa screen at kinakansela ang mga kahilingan sa muling paggamit ng ViewHolder. Ang Coil ay gumagamit ng mga coroutine at may sukat na ~1.5 MB kumpara sa ~4 MB ng Glide, na ginagawa itong mas mainam para sa mga proyektong nakatuon sa laki ng APK.
// Coil — tamad na pag-load ng imahe
imageView.load("https://example.com/image.jpg") {
crossfade(true)
placeholder(R.drawable.placeholder)
size(512, 512)
memoryCachePolicy(CachePolicy.ENABLED)
}
Kingfisher — library para sa iOS na may suporta para sa Swift Concurrency, caching sa disk at memorya, at prefetching para sa UICollectionView. SDWebImage — isang mas lumang library na may mga ugat ng Objective-C ngunit may suporta para sa Swift. Ang parehong library ay sumasama sa UIImageView at awtomatikong namamahala sa lifecycle ng pag-load: kinakansela ang mga kahilingan sa muling paggamit ng cell, nilo-load ang mga imahe lamang kapag ang cell ay nakikita at nagpapalaya ng memorya sa notifikasyon ng kakulangan sa memorya.
Malalaking listahan ng data — ang pangunahing lugar ng aplikasyon ng Lazy Loading sa mga mobile app. News feed, katalogo ng produkto, mga chat, kasaysayan ng transaksyon — bawat screen na may potensyal na walang katapusang listahan ay nangangailangan ng paginasyon at naantalang pag-load.
Paging 3 — library mula sa Android Jetpack na nagpapatupad ng buong cycle ng tamad na pag-load: paghiling ng data mula sa RemoteMediator (API + database), caching sa Room, paghahatid ayon sa pahina sa pamamagitan ng PagingData at pagpapakita sa pamamagitan ng AsyncPagingDataAdapter. Sinusuportahan ng Paging 3 ang tatlong uri ng paginasyon: Page-based (mga pahina), Item-based (offset/limit) at Key-based (mga key ng paginasyon mula sa API). Separator — built-in na suporta para sa mga separator sa pagitan ng mga pahina para sa mga indicator ng pag-load.
// Paging 3 — tamad na pag-load mula sa API
class ArticlePagingSource(
private val api: ArticleApi
) : PagingSource<Int, Article>() {
override suspend fun load(
params: LoadParams<Int>
): LoadResult<Int, Article> {
return try {
val page = params.key ?: 1
val response = api.getArticles(page)
LoadResult.Page(
data = response.items,
prevKey = page.takeIf { it > 1 }?.dec(),
nextKey = page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
LazyVStack — built-in na container ng SwiftUI na gumagawa at nagre-render ng mga elemento lamang kapag lumitaw ang mga ito sa screen. Hindi tulad ng VStack na agad na kinakalkula ang layout ng lahat ng child element, ang LazyVStack ay nagpapaliban sa paggawa ng view hanggang ang elemento ay maging nakikita o pumasok sa prefetch range. LazyHStack — ang pahalang na katapat para sa mga carousel. Para sa malalaking volume ng listahan, inirerekomenda ng Apple ang paggamit ng List na sa loob ay gumagana tulad ng LazyVStack na may dagdag na built-in na recycling.
// SwiftUI — LazyVStack na may tamad na pag-load
ScrollView {
LazyVStack(spacing: 8) {
ForEach(articles) { article in
ArticleRow(article: article)
.onAppear {
if article == articles.last {
viewModel.loadMore()
}
}
}
}
}
Tamad na pag-load ng mga component ng UI — teknik kung saan ang mga bahagi ng interface (mga header, footer, mga seksyon ng setting, mga tab) ay ginagawa hindi sa pagsisimula ng screen, kundi sa unang pag-access sa mga ito. Pinapabilis nito ang paunang render at binabawasan ang karga sa main thread.
ViewStub — isang magaan na View placeholder sa Android na hindi kumukuha ng espasyo sa layout at hindi gumagawa ng child View hanggang sa pagtawag ng inflate(). Mainam para sa mga bihirang ginagamit na seksyon: panel ng paghahanap, mga advanced na setting, mga bloke ng advertisement. Tamad na pag-load ng Fragment — teknik kung saan ang Fragment.onCreateView ay naantala hanggang ang user ay lumipat sa tab na iyon. Ipinapatupad sa pamamagitan ng isVisible o UserVisibleHint sa ViewPager.
AndroidX ay nagbibigay ng SplitInstallManager para sa tamad na pag-load ng mga module kapag hinihingi. Ang mga module ng setting, diagnostic o karagdagang function ay nilo-load bilang Dynamic Feature module lamang sa unang kahilingan ng user. Binabawasan nito ang base size ng app ng 30–50% at sabay na ipinatutupad ang prinsipyo ng Lazy Loading hindi lamang sa antas ng data, kundi pati na rin ng code.
TabView sa SwiftUI ay naglo-load ng nilalaman ng bawat tab nang tamad — lamang kapag na-activate ang tab. Ang UIKit UITabBarController bilang default ay gumagawa ng lahat ng child controller sa pagsisimula, ngunit ang pag-uugaling ito ay maaaring baguhin sa pamamagitan ng hindi pagdaragdag agad sa kanila sa tabBarController.viewControllers, kundi pagdaragdag sa panahon ng paglipat. UIStackView na may arrangedSubviews na dynamic na idinadagdag ay sumusunod din sa prinsipyo ng Lazy Loading — magdagdag ng Subview lamang kapag ang user ay nagsasagawa ng aksyon na nangangailangan ng bahaging iyon ng interface.
Para sa optimisasyon ng pag-load ng screen sa kabuuan, pagsamahin ang Lazy Loading sa lahat ng antas: ViewStub para sa mga bihirang ginagamit na seksyon, Paging 3 para sa data, Glide/Coil para sa mga imahe at tamad na pagsisimula ng ViewModel sa pamamagitan ng Hilt/Dagger Scopes o Swinject. Ang ganitong approach ay nagbibigay ng screen na naglo-load sa 200–400 ms kahit sa mga budget device na may 3 GB ng RAM.
Mga madalas itanong
Kung ang screen ay garantisadong nagpapakita ng kaunting elemento (hanggang 20) at lahat ay kailangan agad — ang Lazy Loading ay kalabisan. Para sa mga listahang bihirang i-scroll, ang Eager Loading ay maaaring mas simple at mas mabilis na ipatupad nang walang kapansin-pansing pagkawala ng pagganap.
Binabawasan ang pinakamataas na konsumo ng memorya ng 3–10 beses para sa malalaking listahan, dahil sa memorya ay nakaimbak lamang ang mga nakikitang elemento at ang prefetch buffer. Gayunpaman, ang pagdaragdag ng prefetch at caching ng mga imahe ay lumilikha ng katamtamang konsumo ng memorya na kailangang pamahalaan.
List ay mas mainam para sa homogenous na data na may kakayahang mag-swipe, mag-drag at built-in na pagpili. LazyVStack — para sa custom na layout na may iba't ibang uri ng cell, seksyon at hindi karaniwang mga puwang. Ang List sa loob ay gumagana tulad ng LazyVStack na may karagdagang functionality.
Sa Android gamitin ang Layout Inspector para tingnan ang hierarchy ng View: sa Lazy Loading karamihan ng mga elemento ay dapat wala sa puno. Sa iOS — Xcode Debug View Hierarchy. Kung habang nag-i-scroll ang lahat ng elemento ay naroroon — hindi gumagana ang Lazy Loading.
Ang parehong parameter ay mahalaga, ngunit ang priyoridad ay depende sa platform. Sa iOS na may ARC at mahusay na pamamahala ng memorya, ang priyoridad ay bilis ng pag-load. Sa Android na may JVM at GC, ang priyoridad ay pagtitipid sa memorya, dahil ang bawat alokasyon sa main thread ay maaaring magdulot ng GC-freeze.
Buod
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.
Basahin din