Lazy Loading no desenvolvimento mobile — como funciona, princípios e implementação

Autor: IT Sectr Publicado: 2026-04-01 Tempo de leitura: 9 min

Lazy Loading é uma estratégia de carregamento diferido de dados, imagens e componentes, na qual os recursos não são solicitados na inicialização do aplicativo, mas no momento em que o usuário realmente precisa deles. De acordo com o Guia do Android Paging 3, o carregamento diferido de listas reduz o consumo de memória em 60–80% ao trabalhar com grandes conjuntos de dados. A inicialização diferida é o princípio-chave que fundamenta todas as implementações de Lazy Loading.

Principais pontos

  • Lazy Loading é um padrão de carregamento diferido que economiza memória e acelera a primeira inicialização
  • LazyVStack e LazyHStack são componentes nativos do SwiftUI para listas diferidas
  • Paging 3 é uma biblioteca Android para carregamento paginado de dados de API e banco de dados
  • Bibliotecas de imagens (Glide, Coil, Kingfisher) carregam imagens apenas quando aparecem na tela
  • Pré-carregamento é o carregamento antecipado, o lado oposto do Lazy Loading para uma UX fluida

O que é Lazy Loading

Lazy Loading (carregamento diferido ou preguiçoso) é um padrão de design e otimização no qual os recursos do aplicativo não são carregados na inicialização, mas imediatamente antes do uso. No desenvolvimento mobile, o Lazy Loading se aplica a três categorias principais: dados (paginação de listas), imagens (carregamento ao rolar) e componentes (pilhas e visualizações diferidas).

O oposto do Lazy Loading é o Eager Loading (carregamento antecipado), onde todos os recursos são carregados na inicialização da tela. O Eager Loading é mais simples de implementar, mas consome mais memória e aumenta o tempo de primeira exibição. Para listas com milhares de itens, o Eager Loading leva a OOM (Out of Memory) em dispositivos com memória limitada. O Lazy Loading resolve esse problema carregando apenas o que está visível na tela e carregando o resto à medida que o usuário rola.

No contexto de iOS e Android, o Lazy Loading é implementado em diferentes níveis. O SwiftUI fornece LazyVStack e LazyHStack para renderização diferida. O UIKit usa UITableView com dequeueReusableCell. O Android usa RecyclerView com um pool de ViewHolder. No nível de dados, Room com Paging 3 e Core Data com NSFetchedResultsController. A escolha da tecnologia específica depende da pilha e dos requisitos de desempenho.

Princípios de funcionamento do carregamento diferido

O princípio central do Lazy Loading é carregar exatamente a quantidade de dados necessária para o estado atual da tela, mais um buffer antecipado para rolagem suave. Esta abordagem baseia-se em dois mecanismos: rastreamento de visibilidade e virtualização de elementos.

Rastreamento de visibilidade

O mecanismo de rastreamento determina quais elementos estão na área visível da tela (viewport). No Android, isso é feito pelo LinearLayoutManager ou GridLayoutManager através dos métodos findFirstVisibleItemPosition e findLastVisibleItemPosition. No iOS, o UIScrollView fornece bounds.origin.y e contentOffset.height para calcular a área visível. Quando um elemento entra no viewport (ou no buffer de pré-busca), seu carregamento é iniciado. Quando um elemento sai da tela, seus recursos podem ser liberados ou movidos para o cache.

kotlin
// Android — rastreamento de visibilidade no 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
        // Carregando a próxima página se restarem < 5 itens
        if (lastVisible >= totalCount - 5) {
            loadMoreItems()
        }
    }
})

Buffer e pré-busca

O buffer de pré-busca é o carregamento antecipado de elementos que aparecerão em breve na tela. O RecyclerView suporta GapWorker.Prefetch através de layoutManager.setItemPrefetchEnabled(true). O iOS UITableView suporta pré-busca através de UITableViewDataSourcePrefetching. O tamanho do buffer de pré-busca é tipicamente de 1 a 2 telas à frente, proporcionando um compromisso entre suavidade de rolagem e consumo de memória. Um buffer de pré-busca muito grande anula as vantagens do Lazy Loading; um muito pequeno cria espaços em branco durante a rolagem rápida.

Lazy Loading de imagens

Imagens são o tipo de recurso mais pesado em aplicativos móveis. Uma única foto de 12 MP pode ocupar de 3 a 5 MB em formato não comprimido. O Lazy Loading de imagens evita carregar centenas de imagens invisíveis na memória, o que seria fatal para listas com avatares de usuários ou catálogos de produtos.

Bibliotecas para Android: Glide e Coil

Glide é a biblioteca de carregamento de imagens mais popular para Android, com suporte a cache, transformações e animações. Coil é uma alternativa mais leve, escrita em Kotlin usando corrotinas. Ambas as bibliotecas pausam automaticamente o carregamento quando um ImageView sai da tela e cancelam as requisições quando um ViewHolder é reutilizado. O Coil usa corrotinas e tem ~1,5 MB contra ~4 MB do Glide, tornando-o preferível para projetos focados no tamanho do APK.

kotlin
// Coil — carregamento diferido de imagens
imageView.load("https://example.com/image.jpg") {
    crossfade(true)
    placeholder(R.drawable.placeholder)
    size(512, 512)
    memoryCachePolicy(CachePolicy.ENABLED)
}

Bibliotecas para iOS: Kingfisher e SDWebImage

Kingfisher é uma biblioteca para iOS com suporte a Swift Concurrency, cache em disco e memória, e pré-busca para UICollectionView. SDWebImage é uma biblioteca mais antiga com raízes em Objective-C, mas com suporte a Swift. Ambas as bibliotecas se integram com UIImageView e gerenciam automaticamente o ciclo de vida do carregamento: cancelam requisições quando uma célula é reutilizada, carregam imagens apenas quando a célula está visível e liberam memória ao receber um aviso de memória insuficiente.

Lazy Loading de dados e listas

Listas grandes de dados são o principal campo de aplicação do Lazy Loading em aplicativos móveis. Feed de notícias, catálogo de produtos, chats, histórico de transações — qualquer tela com uma lista potencialmente infinita requer paginação e carregamento diferido.

Paging 3 para Android

Paging 3 é uma biblioteca do Android Jetpack que implementa o ciclo completo de carregamento diferido: requisição de dados do RemoteMediator (API + banco de dados), cache no Room, saída página por página via PagingData e exibição através de AsyncPagingDataAdapter. O Paging 3 suporta três tipos de paginação: baseada em páginas, baseada em itens (offset/limit) e baseada em chaves (chaves de paginação da API). Separator é o suporte nativo para separadores entre páginas para indicadores de carregamento.

kotlin
// Paging 3 — carregamento diferido de 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 e LazyHStack

LazyVStack é um contêiner nativo do SwiftUI que cria e renderiza elementos apenas quando eles aparecem na tela. Ao contrário do VStack, que calcula imediatamente o layout de todos os elementos filhos, o LazyVStack adia a criação da view até que o elemento se torne visível ou entre no intervalo de pré-busca. LazyHStack é o equivalente horizontal para carrosséis. Para listas grandes, a Apple recomenda usar List, que internamente funciona de forma similar ao LazyVStack com reciclagem nativa adicional.

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

Lazy Loading de componentes de UI

Carregamento diferido de componentes de UI é uma técnica onde partes da interface (cabeçalhos, rodapés, seções de configuração, abas) não são criadas na inicialização da tela, mas no primeiro acesso. Isso acelera a renderização inicial e reduz a carga na thread principal.

Android: ViewStub e carregamento diferido de Fragment

ViewStub é um placeholder de View leve no Android que não ocupa espaço no layout e não cria Views filhas até que inflate() seja chamado. É ideal para seções raramente usadas: painel de busca, configurações avançadas, blocos de anúncios. O carregamento diferido de Fragment é uma técnica onde Fragment.onCreateView é adiado até que o usuário mude para aquela aba. É implementado via isVisible ou UserVisibleHint no ViewPager.

AndroidX fornece SplitInstallManager para carregamento diferido de módulos sob demanda. Módulos de configuração, diagnóstico ou funcionalidades adicionais são carregados como módulos Dynamic Feature apenas na primeira solicitação do usuário. Isso reduz o tamanho base do aplicativo em 30–50% e simultaneamente implementa o princípio do Lazy Loading não apenas no nível de dados, mas também no nível de código.

iOS: TabView e a natureza diferida do ViewBuilder

TabView no SwiftUI carrega o conteúdo de cada aba de forma diferida — apenas quando a aba é ativada. O UIKit UITabBarController cria todos os controladores filhos na inicialização por padrão, mas esse comportamento pode ser alterado não os adicionando imediatamente a tabBarController.viewControllers e substituindo-os conforme o usuário alterna. UIStackView com arrangedSubviews adicionados dinamicamente também segue o princípio do Lazy Loading — adicione uma Subview apenas quando o usuário realizar uma ação que exija aquela parte da interface.

Para otimizar o carregamento geral da tela, combine Lazy Loading em todos os níveis: ViewStub para seções raramente usadas, Paging 3 para dados, Glide/Coil para imagens e inicialização diferida de ViewModel através de Hilt/Dagger Scopes ou Swinject. Esta abordagem produz uma tela que carrega em 200–400 ms mesmo em dispositivos econômicos com 3 GB de RAM.

Perguntas frequentes

Quando não usar Lazy Loading?

Se a tela garante mostrar poucos itens (até 20) e todos são necessários imediatamente, o Lazy Loading é desnecessário. Para listas que raramente são roladas, o Eager Loading pode ser mais simples e rápido de implementar sem perda perceptível de desempenho.

Como o Lazy Loading afeta a memória?

Reduz o consumo máximo de memória em 3 a 10 vezes para listas grandes, pois apenas os elementos visíveis mais o buffer de pré-busca são armazenados na memória. No entanto, adicionar pré-busca e cache de imagens cria um consumo moderado de memória que precisa ser gerenciado.

O que escolher — LazyVStack ou List no SwiftUI?

List é preferível para dados homogêneos com suporte a deslizar, arrastar e soltar e seleção nativa. LazyVStack é para layouts personalizados com diferentes tipos de célula, seções e espaçamentos não padrão. O List internamente funciona como LazyVStack com funcionalidade adicional.

Como depurar problemas de carregamento diferido?

No Android, use o Layout Inspector para ver a hierarquia de View: com Lazy Loading, a maioria dos elementos deve estar ausente da árvore. No iOS, use Xcode Debug View Hierarchy. Se todos os elementos estiverem presentes durante a rolagem, o Lazy Loading não está funcionando.

O que é mais importante — velocidade de carregamento ou economia de memória?

Ambos os parâmetros são importantes, mas a prioridade depende da plataforma. No iOS com ARC e gerenciamento eficiente de memória, a prioridade é a velocidade de carregamento. No Android com JVM e GC, a prioridade é a economia de memória, pois cada alocação na thread principal pode causar um congelamento do GC.

Resumo

  • Lazy Loading é um padrão de carregamento diferido que acelera a primeira inicialização e economiza memória
  • Imagens são carregadas via Glide, Coil, Kingfisher apenas quando entram no viewport
  • Paging 3 para Android fornece carregamento paginado de dados com cache no Room
  • LazyVStack no SwiftUI adia a renderização de elementos até que apareçam na tela
  • ViewStub no Android — carregamento diferido de componentes de UI no primeiro acesso
  • Buffer de pré-busca — carregamento antecipado para rolagem suave
  • Combine Lazy Loading em todos os níveis: dados + imagens + UI

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também