Lazy Loading i mobilutveckling — hur det fungerar, principer och implementering

Författare: IT Sectr Publicerad: 2026-04-01 Lästid: 9 min

Lazy Loading — en strategi för fördröjd laddning av data, bilder och komponenter, där resurser inte efterfrågas vid appstart utan när användaren verkligen behöver dem. Enligt Android Paging 3 Guide minskar lat lastning av listor minnesförbrukningen med 60–80% vid arbete med stora datamängder. Fördröjd initiering — den centrala principen bakom alla Lazy Loading-implementeringar.

Huvudpunkter

  • Lazy Loading — mönster för fördröjd laddning som sparar minne och snabbar upp första starten
  • LazyVStack och LazyHStack — inbyggda SwiftUI-komponenter för lata listor
  • Paging 3 — Android-bibliotek för sidvis laddning av data från API och databas
  • Bildbibliotek (Glide, Coil, Kingfisher) laddar bilder först när de visas på skärmen
  • Preloading — förhandsloadning, den andra sidan av Lazy Loading för smidig UX

Vad är Lazy Loading

Lazy Loading (lat lastning, fördröjd laddning) — ett design- och optimeringsmönster där appresurser laddas inte vid start, utan omedelbart före användning. Inom mobilutveckling tillämpas Lazy Loading på tre huvudkategorier: data (pagering av listor), bilder (laddning vid scrollning) och komponenter (lata stackar och vyer).

Motsatsen till Lazy Loading är Eager Loading (ivrig laddning), när alla resurser laddas vid skärmstart. Eager Loading är enklare att implementera men förbrukar mer minne och ökar tiden för första visningen. För listor med tusentals element leder Eager Loading till OOM (Out of Memory) på enheter med begränsat minne. Lazy Loading löser detta problem genom att bara ladda det som syns på skärmen och lägga till resten under scrollning.

I kontexten av iOS och Android är Lazy Loading implementerat på olika nivåer. SwiftUI tillhandahåller LazyVStack och LazyHStack för lat rendering. UIKit använder UITableView med dequeueReusableCell. Android — RecyclerView med ViewHolder-pool. På datanivå — Room med Paging 3 och Core Data med NSFetchedResultsController. Valet av specifik teknik beror på stacken och prestandakraven.

Principer för lat lastning

Den centrala principen för Lazy Loading — ladda exakt den mängd data som behövs för skärmens aktuella tillstånd, plus en förhandsbuffer för smidig scrollning. Denna metod bygger på två mekanismer: synlighetsövervakning och virtualisering av element.

Synlighetsövervakning

Övervakningsmekanismen avgör vilka element som finns i skärmens synliga område (viewport). På Android gör LinearLayoutManager eller GridLayoutManager detta via metoderna findFirstVisibleItemPosition och findLastVisibleItemPosition. I iOS tillhandahåller UIScrollView bounds.origin.y och contentOffset.height för att beräkna det synliga området. När ett element kommer in i viewport (eller prefetch-bufferten) startas dess laddning. När elementet lämnar skärmen kan dess resurser frigöras eller flyttas till cachen.

kotlin
// Android — synlighetsövervakning i 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
        // Vi laddar nästa sida om färre än 5 element återstår < 5 element
        if (lastVisible >= totalCount - 5) {
            loadMoreItems()
        }
    }
})

Buffring och prefetch

Prefetch-buffert — förhandsloadning av element som snart kommer att visas på skärmen. RecyclerView stöder GapWorker.Prefetch via layoutManager.setItemPrefetchEnabled(true). iOS UITableView stöder prefetching via UITableViewDataSourcePrefetching. Prefetch-buffertens storlek är vanligtvis 1–2 skärmar framåt, vilket ger en kompromiss mellan scrollningssmidighet och minnesförbrukning. För stor prefetch-buffert förstör fördelarna med Lazy Loading, för liten — skapar tomma utrymmen vid snabb scrollning.

Lazy Loading av bilder

Bilder — den tyngsta resurstypen i mobilappar. Ett 12 MP-foto kan ta 3–5 MB i okomprimerad form. Lazy Loading av bilder förhindrar laddning av hundratals osynliga bilder i minnet, vilket skulle vara katastrofalt för listor med användarkommentarer eller produktkataloger.

Bibliotek för Android: Glide och Coil

Glide — det populäraste bildladdningsbiblioteket för Android med stöd för cachning, transformationer och animationer. Coil — ett lättare alternativ skrivet i Kotlin med hjälp av korutiner. Båda biblioteken stoppar automatiskt laddning när ImageView lämnar skärmen och avbryter förfrågningar vid återanvändning av ViewHolder. Coil använder korutiner och är ~1.5 MB mot ~4 MB för Glide, vilket gör det att föredra för projekt som fokuserar på APK-storlek.

kotlin
// Coil — lat lastning av bild
imageView.load("https://example.com/image.jpg") {
    crossfade(true)
    placeholder(R.drawable.placeholder)
    size(512, 512)
    memoryCachePolicy(CachePolicy.ENABLED)
}

Bibliotek för iOS: Kingfisher och SDWebImage

Kingfisher — bibliotek för iOS med stöd för Swift Concurrency, cachning på disk och i minne, samt prefetching för UICollectionView. SDWebImage — ett äldre bibliotek med Objective-C-rötter men med stöd för Swift. Båda biblioteken integreras med UIImageView och hanterar automatiskt laddningslivscykeln: avbryter förfrågningar vid cellåteranvändning, laddar bilder endast när cellen är synlig och frigör minne vid meddelande om minnesbrist.

Lazy Loading av data och listor

Stora datalistor — det främsta tillämpningsområdet för Lazy Loading i mobilappar. Nyhetsflöde, produktkatalog, chattar, transaktionshistorik — varje skärm med en potentiellt oändlig lista kräver pagering och fördröjd laddning.

Paging 3 för Android

Paging 3 — bibliotek från Android Jetpack som implementerar hela cykeln för lat lastning: dataförfrågan från RemoteMediator (API + databas), cachning i Room, sidvis leverans via PagingData och visning via AsyncPagingDataAdapter. Paging 3 stöder tre typer av pagering: Page-based (sidor), Item-based (offset/limit) och Key-based (pageringsnycklar från API). Separator — inbyggt stöd för avskiljare mellan sidor för laddningsindikatorer.

kotlin
// Paging 3 — lat lastning från 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)
        }
    }
}

SwiftUI LazyVStack och LazyHStack

LazyVStack — inbyggd SwiftUI-container som skapar och renderar element först när de visas på skärmen. Till skillnad från VStack, som omedelbart beräknar layouten för alla underordnade element, skjuter LazyVStack upp skapandet av vyn tills elementet blir synligt eller kommer in i prefetch-området. LazyHStack — den horisontella motsvarigheten för karuseller. För listor med stor volym rekommenderar Apple att använda List, som internt fungerar som LazyVStack med ytterligare inbyggd återvinning.

swift
// SwiftUI — LazyVStack med lat lastning
ScrollView {
    LazyVStack(spacing: 8) {
        ForEach(articles) { article in
            ArticleRow(article: article)
                .onAppear {
                    if article == articles.last {
                        viewModel.loadMore()
                    }
                }
        }
    }
}

Lazy Loading av UI-komponenter

Lat lastning av UI-komponenter — teknik där delar av gränssnittet (sidhuvuden, sidfötter, inställningssektioner, flikar) skapas inte vid skärmstart utan vid första åtkomst till dem. Detta snabbar upp den initiala renderingen och minskar belastningen på huvudtråden.

Android: ViewStub och lat lastning av Fragment

ViewStub — en lätt View-platshållare i Android som inte tar plats i layouten och inte skapar underordnade Views förrän anrop av inflate(). Idealisk för sällan använda sektioner: sökpanel, avancerade inställningar, reklamblock. Lat lastning av Fragment — teknik där Fragment.onCreateView skjuts upp tills användaren växlar till den fliken. Implementeras via isVisible eller UserVisibleHint i ViewPager.

AndroidX tillhandahåller SplitInstallManager för lat lastning av moduler på begäran. Moduler för inställningar, diagnostik eller extra funktioner laddas som Dynamic Feature-moduler endast vid användarens första begäran. Detta minskar appens basstorlek med 30–50% och implementerar samtidigt principen för Lazy Loading inte bara på datanivå utan även på kodnivå.

iOS: TabView och ViewBuilder-lathet

TabView i SwiftUI laddar innehållet på varje flik lat — endast vid flikaktivering. UIKit UITabBarController skapar som standard alla underordnade kontroller vid start, men detta beteende kan ändras genom att inte lägga till dem omedelbart i tabBarController.viewControllers utan lägga till dem vid växling. UIStackView med dynamiskt tillagda arrangedSubviews följer också principen för Lazy Loading — lägg till Subview endast när användaren utför en åtgärd som kräver den delen av gränssnittet.

För att optimera skärmladdningen som helhet, kombinera Lazy Loading på alla nivåer: ViewStub för sällan använda sektioner, Paging 3 för data, Glide/Coil för bilder och lat initiering av ViewModel via Hilt/Dagger Scopes eller Swinject. Ett sådant tillvägagångssätt ger en skärm som laddas på 200–400 ms även på budgetenheter med 3 GB RAM.

Vanliga frågor

När ska jag inte använda Lazy Loading?

Om skärmen garanterat visar få element (upp till 20) och alla behövs omedelbart — är Lazy Loading överflödigt. För listor som sällan scrollas kan Eager Loading vara enklare och snabbare att implementera utan märkbar prestandaförlust.

Hur påverkar Lazy Loading minnet?

Minskar toppminnesförbrukningen 3–10 gånger för stora listor, eftersom endast synliga element plus prefetch-bufferten lagras i minnet. Att lägga till prefetch och cachning av bilder skapar dock en måttlig minnesförbrukning som måste hanteras.

Vad ska jag välja — LazyVStack eller List i SwiftUI?

List är att föredra för homogen data med möjlighet till svep, drag och inbyggt urval. LazyVStack — för anpassade layouter med olika celltyper, sektioner och icke-standardiserade mellanrum. List fungerar internt som LazyVStack med ytterligare funktionalitet.

Hur felsöker jag problem med lat lastning?

I Android använder du Layout Inspector för att visa View-hierarkin: vid Lazy Loading bör de flesta element saknas i trädet. I iOS — Xcode Debug View Hierarchy. Om alla element finns när du scrollar — fungerar inte Lazy Loading.

Vad är viktigast — laddningshastighet eller minnesbesparing?

Båda parametrarna är viktiga, men prioriteten beror på plattformen. På iOS med ARC och effektiv minneshantering är prioriteten laddningshastighet. På Android med JVM och GC är prioriteten minnesbesparing, eftersom varje allokering i huvudtråden kan orsaka GC-frysning.

Sammanfattning

  • Lazy Loading — mönster för fördröjd laddning som snabbar upp första starten och sparar minne
  • Bilder laddas via Glide, Coil, Kingfisher endast vid inmatning i viewport
  • Paging 3 för Android ger sidvis laddning av data med cachning i Room
  • LazyVStack i SwiftUI skjuter upp rendering av element tills de visas på skärmen
  • ViewStub i Android — lat lastning av UI-komponenter vid första åtkomst
  • Prefetch-buffert — förhandsloadning för smidig scrollning
  • Kombinera Lazy Loading på alla nivåer: data + bilder + UI

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också